1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Depth and stencil clear tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2fDepthStencilClearTests.hpp"
25
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluRenderContext.hpp"
29
30 #include "tcuTestLog.hpp"
31 #include "tcuTexture.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "tcuImageCompare.hpp"
34 #include "tcuSurface.hpp"
35 #include "tcuRenderTarget.hpp"
36
37 #include "deRandom.hpp"
38 #include "deMath.h"
39 #include "deString.h"
40
41 #include "glwFunctions.hpp"
42 #include "glwEnums.hpp"
43
44 namespace deqp
45 {
46 namespace gles2
47 {
48 namespace Functional
49 {
50
51 using std::string;
52 using std::vector;
53 using tcu::TestLog;
54 using tcu::Vec3;
55 using tcu::Vec4;
56
57 namespace
58 {
59
60 enum
61 {
62 STENCIL_STEPS = 32,
63 DEPTH_STEPS = 32
64 };
65
66 struct Clear
67 {
Cleardeqp::gles2::Functional::__anon997496580111::Clear68 Clear(void)
69 : clearMask(0)
70 , clearDepth(0.0f)
71 , clearStencil(0)
72 , useScissor(false)
73 , scissor(0, 0, 0, 0)
74 , depthMask(false)
75 , stencilMask(0)
76 {
77 }
78
79 uint32_t clearMask;
80 float clearDepth;
81 int clearStencil;
82
83 bool useScissor;
84 tcu::IVec4 scissor;
85
86 bool depthMask;
87 uint32_t stencilMask;
88 };
89
getDepthFormat(int depthBits)90 tcu::TextureFormat getDepthFormat(int depthBits)
91 {
92 switch (depthBits)
93 {
94 case 8:
95 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
96 case 16:
97 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
98 case 24:
99 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24);
100 case 32:
101 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
102 default:
103 TCU_FAIL("Can't map depth buffer format");
104 }
105 }
106
getStencilFormat(int stencilBits)107 tcu::TextureFormat getStencilFormat(int stencilBits)
108 {
109 switch (stencilBits)
110 {
111 case 8:
112 return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
113 case 16:
114 return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT16);
115 case 24:
116 return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT24);
117 case 32:
118 return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32);
119 default:
120 TCU_FAIL("Can't map depth buffer format");
121 }
122 }
123
124 } // namespace
125
126 class DepthStencilClearCase : public TestCase
127 {
128 public:
129 DepthStencilClearCase(Context &context, const char *name, const char *description, int numIters, int numClears,
130 bool depth, bool stencil, bool scissor, bool masked);
131 ~DepthStencilClearCase(void);
132
133 void init(void);
134 void deinit(void);
135
136 IterateResult iterate(void);
137
138 private:
139 void generateClears(vector<Clear> &dst, uint32_t seed);
140 void renderGL(tcu::Surface &dst, const vector<Clear> &clears);
141 void renderReference(tcu::Surface &dst, const vector<Clear> &clears);
142
143 bool m_testDepth;
144 bool m_testStencil;
145 bool m_testScissor;
146 bool m_masked;
147 int m_numIters;
148 int m_numClears;
149 int m_curIter;
150
151 glu::ShaderProgram *m_visProgram;
152 };
153
DepthStencilClearCase(Context & context,const char * name,const char * description,int numIters,int numClears,bool depth,bool stencil,bool scissor,bool masked)154 DepthStencilClearCase::DepthStencilClearCase(Context &context, const char *name, const char *description, int numIters,
155 int numClears, bool depth, bool stencil, bool scissor, bool masked)
156 : TestCase(context, name, description)
157 , m_testDepth(depth)
158 , m_testStencil(stencil)
159 , m_testScissor(scissor)
160 , m_masked(masked)
161 , m_numIters(numIters)
162 , m_numClears(numClears)
163 , m_curIter(0)
164 , m_visProgram(DE_NULL)
165 {
166 }
167
~DepthStencilClearCase(void)168 DepthStencilClearCase::~DepthStencilClearCase(void)
169 {
170 DepthStencilClearCase::deinit();
171 }
172
init(void)173 void DepthStencilClearCase::init(void)
174 {
175 TestLog &log = m_testCtx.getLog();
176
177 m_visProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
178 // Vertex shader.
179 "attribute highp vec4 a_position;\n"
180 "void main (void)\n"
181 "{\n"
182 " gl_Position = a_position;\n"
183 "}\n",
184
185 // Fragment shader.
186 "uniform mediump vec4 u_color;\n"
187 "void main (void)\n"
188 "{\n"
189 " gl_FragColor = u_color;\n"
190 "}\n"));
191
192 if (!m_visProgram->isOk())
193 {
194 log << *m_visProgram;
195 delete m_visProgram;
196 m_visProgram = DE_NULL;
197 TCU_FAIL("Compile failed");
198 }
199
200 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
201 }
202
deinit(void)203 void DepthStencilClearCase::deinit(void)
204 {
205 delete m_visProgram;
206 m_visProgram = DE_NULL;
207 }
208
iterate(void)209 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate(void)
210 {
211 const tcu::RenderTarget &renderTarget = m_context.getRenderTarget();
212 int width = renderTarget.getWidth();
213 int height = renderTarget.getHeight();
214 tcu::Surface result(width, height);
215 tcu::Surface reference(width, height);
216 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
217 vector<Clear> clears;
218
219 if ((m_testDepth && renderTarget.getDepthBits() == 0) || (m_testStencil && renderTarget.getStencilBits() == 0))
220 throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__);
221
222 generateClears(clears, deStringHash(getName()) ^ deInt32Hash(m_curIter));
223 renderGL(result, clears);
224 renderReference(reference, clears);
225
226 bool isLastIter = m_curIter + 1 == m_numIters;
227 bool isOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result,
228 threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
229
230 if (!isOk)
231 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
232
233 m_curIter += 1;
234 return isLastIter || !isOk ? STOP : CONTINUE;
235 }
236
generateClears(vector<Clear> & clears,uint32_t seed)237 void DepthStencilClearCase::generateClears(vector<Clear> &clears, uint32_t seed)
238 {
239 const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
240 int width = renderTarget.getWidth();
241 int height = renderTarget.getHeight();
242 de::Random rnd(seed);
243
244 clears.resize(m_numClears);
245
246 for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++)
247 {
248 if (m_testScissor)
249 {
250 int w = rnd.getInt(1, width);
251 int h = rnd.getInt(1, height);
252 int x = rnd.getInt(0, width - w);
253 int y = rnd.getInt(0, height - h);
254
255 clear->useScissor = true; // \todo [pyry] Should we randomize?
256 clear->scissor = tcu::IVec4(x, y, w, h);
257 }
258 else
259 clear->useScissor = false;
260
261 clear->clearDepth = rnd.getFloat(-0.2f, 1.2f);
262 clear->clearStencil = rnd.getUint32();
263
264 clear->depthMask = m_masked ? rnd.getBool() : true;
265 clear->stencilMask = m_masked ? rnd.getUint32() : 0xffffffffu;
266
267 if (m_testDepth && m_testStencil)
268 {
269 switch (rnd.getInt(0, 2))
270 {
271 case 0:
272 clear->clearMask = GL_DEPTH_BUFFER_BIT;
273 break;
274 case 1:
275 clear->clearMask = GL_STENCIL_BUFFER_BIT;
276 break;
277 case 2:
278 clear->clearMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
279 break;
280 }
281 }
282 else if (m_testDepth)
283 clear->clearMask = GL_DEPTH_BUFFER_BIT;
284 else
285 {
286 DE_ASSERT(m_testStencil);
287 clear->clearMask = GL_STENCIL_BUFFER_BIT;
288 }
289 }
290 }
291
renderGL(tcu::Surface & dst,const vector<Clear> & clears)292 void DepthStencilClearCase::renderGL(tcu::Surface &dst, const vector<Clear> &clears)
293 {
294 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
295 int colorLoc = gl.getUniformLocation(m_visProgram->getProgram(), "u_color");
296 int positionLoc = gl.getAttribLocation(m_visProgram->getProgram(), "a_position");
297 static const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
298
299 // Clear with default values.
300 gl.clearDepthf(1.0f);
301 gl.clearStencil(0);
302 gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
303 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
304
305 GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears");
306
307 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
308 {
309 if (clear->useScissor)
310 {
311 gl.enable(GL_SCISSOR_TEST);
312 gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w());
313 }
314
315 // Clear values.
316 gl.clearDepthf(clear->clearDepth);
317 gl.clearStencil(clear->clearStencil);
318
319 // Masks.
320 gl.depthMask(clear->depthMask ? GL_TRUE : GL_FALSE);
321 gl.stencilMask(clear->stencilMask);
322
323 // Execute clear.
324 gl.clear(clear->clearMask);
325
326 if (clear->useScissor)
327 gl.disable(GL_SCISSOR_TEST);
328 }
329
330 // Restore default masks.
331 gl.depthMask(GL_TRUE);
332 gl.stencilMask(0xffffffffu);
333
334 GLU_EXPECT_NO_ERROR(gl.getError(), "After clears");
335
336 gl.useProgram(m_visProgram->getProgram());
337 gl.enableVertexAttribArray(positionLoc);
338
339 // Visualize depth / stencil buffers.
340 if (m_testDepth)
341 {
342 int numSteps = DEPTH_STEPS;
343 float step = 2.0f / (float)numSteps;
344
345 gl.enable(GL_DEPTH_TEST);
346 gl.depthFunc(GL_LESS);
347 gl.depthMask(GL_FALSE);
348 gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
349
350 for (int ndx = 0; ndx < numSteps; ndx++)
351 {
352 float d = -1.0f + step * (float)ndx;
353 float c = (float)ndx / (float)(numSteps - 1);
354 float pos[] = {-1.0f, -1.0f, d, -1.0f, 1.0f, d, 1.0f, -1.0f, d, 1.0f, 1.0f, d};
355
356 gl.uniform4f(colorLoc, 0.0f, 0.0f, c, 1.0f);
357 gl.vertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]);
358 gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
359 }
360
361 gl.disable(GL_DEPTH_TEST);
362 gl.depthMask(GL_TRUE);
363
364 GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization");
365 }
366
367 if (m_testStencil)
368 {
369 int numSteps = STENCIL_STEPS;
370 int numValues = (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits
371 int step = numValues / numSteps;
372
373 gl.enable(GL_STENCIL_TEST);
374 gl.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
375 gl.colorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
376
377 static const float pos[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
378 gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]);
379
380 for (int ndx = 0; ndx < numSteps; ndx++)
381 {
382 int s = step * ndx;
383 float c = (float)ndx / (float)(numSteps - 1);
384
385 gl.stencilFunc(GL_LEQUAL, s, 0xffu);
386 gl.uniform4f(colorLoc, 0.0f, c, 0.0f, 1.0f);
387 gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
388 }
389
390 gl.disable(GL_STENCIL_TEST);
391
392 GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization");
393 }
394
395 // Restore color mask (changed by visualization).
396 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
397
398 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
399 }
400
renderReference(tcu::Surface & dst,const vector<Clear> & clears)401 void DepthStencilClearCase::renderReference(tcu::Surface &dst, const vector<Clear> &clears)
402 {
403 glu::RenderContext &renderCtx = TestCase::m_context.getRenderContext();
404 const tcu::RenderTarget &renderTarget = renderCtx.getRenderTarget();
405
406 // Clear surface to red.
407 tcu::clear(dst.getAccess(), tcu::RGBA::red().toVec());
408
409 if (m_testDepth)
410 {
411 // Simulated depth buffer span.
412 tcu::TextureLevel depthBufRow(getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1);
413 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess();
414
415 for (int y = 0; y < dst.getHeight(); y++)
416 {
417 // Clear to default value.
418 for (int x = 0; x < rowAccess.getWidth(); x++)
419 rowAccess.setPixel(Vec4(1.0f), x, 0);
420
421 // Execute clears.
422 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
423 {
424 // Clear / mask test.
425 if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask)
426 continue;
427
428 tcu::IVec4 clearRect =
429 clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
430
431 // Intersection test.
432 if (!de::inBounds(y, clearRect.y(), clearRect.y() + clearRect.w()))
433 continue;
434
435 for (int x = clearRect.x(); x < clearRect.x() + clearRect.z(); x++)
436 rowAccess.setPixDepth(de::clamp(clear->clearDepth, 0.0f, 1.0f), x, 0);
437 }
438
439 // Map to colors.
440 for (int x = 0; x < dst.getWidth(); x++)
441 {
442 float depth = rowAccess.getPixDepth(x, 0);
443 float step = deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS - 1);
444 tcu::RGBA oldColor = dst.getPixel(x, y);
445 tcu::RGBA newColor =
446 tcu::RGBA(oldColor.getRed(), oldColor.getGreen(),
447 deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha());
448
449 dst.setPixel(x, y, newColor);
450 }
451 }
452 }
453
454 if (m_testStencil)
455 {
456 // Simulated stencil buffer span.
457 int stencilBits = renderTarget.getStencilBits();
458 tcu::TextureLevel depthBufRow(getStencilFormat(stencilBits), dst.getWidth(), 1, 1);
459 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess();
460 uint32_t bufMask = (1u << stencilBits) - 1;
461
462 for (int y = 0; y < dst.getHeight(); y++)
463 {
464 // Clear to default value.
465 for (int x = 0; x < rowAccess.getWidth(); x++)
466 rowAccess.setPixel(tcu::UVec4(0), x, 0);
467
468 // Execute clears.
469 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
470 {
471 // Clear / mask test.
472 if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0)
473 continue;
474
475 tcu::IVec4 clearRect =
476 clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
477
478 // Intersection test.
479 if (!de::inBounds(y, clearRect.y(), clearRect.y() + clearRect.w()))
480 continue;
481
482 for (int x = clearRect.x(); x < clearRect.x() + clearRect.z(); x++)
483 {
484 uint32_t oldVal = rowAccess.getPixStencil(x, 0);
485 uint32_t newVal =
486 ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask;
487 rowAccess.setPixStencil(newVal, x, 0);
488 }
489 }
490
491 // Map to colors.
492 for (int x = 0; x < dst.getWidth(); x++)
493 {
494 uint32_t stencil = rowAccess.getPixStencil(x, 0);
495 float step =
496 (float)(stencil / ((1u << stencilBits) / (uint32_t)STENCIL_STEPS)) / (float)(STENCIL_STEPS - 1);
497 tcu::RGBA oldColor = dst.getPixel(x, y);
498 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255),
499 oldColor.getBlue(), oldColor.getAlpha());
500
501 dst.setPixel(x, y, newColor);
502 }
503 }
504 }
505 }
506
DepthStencilClearTests(Context & context)507 DepthStencilClearTests::DepthStencilClearTests(Context &context)
508 : TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
509 {
510 }
511
init(void)512 void DepthStencilClearTests::init(void)
513 {
514 // iters clears depth stencil scissor masked
515 addChild(new DepthStencilClearCase(m_context, "depth", "", 4, 2, true, false, false, false));
516 addChild(new DepthStencilClearCase(m_context, "depth_scissored", "", 4, 16, true, false, true, false));
517 addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked", "", 4, 16, true, false, true, true));
518
519 addChild(new DepthStencilClearCase(m_context, "stencil", "", 4, 2, false, true, false, false));
520 addChild(new DepthStencilClearCase(m_context, "stencil_masked", "", 4, 8, false, true, false, true));
521 addChild(new DepthStencilClearCase(m_context, "stencil_scissored", "", 4, 16, false, true, true, false));
522 addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked", "", 4, 16, false, true, true, true));
523
524 addChild(new DepthStencilClearCase(m_context, "depth_stencil", "", 4, 2, true, true, false, false));
525 addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked", "", 4, 8, true, true, false, true));
526 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored", "", 4, 16, true, true, true, false));
527 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked", "", 4, 16, true, true, true, true));
528 }
529
530 } // namespace Functional
531 } // namespace gles2
532 } // namespace deqp
533