1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.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 "es3fDepthStencilClearTests.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 gles3
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::gles3::Functional::__anonde2a0efa0111::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 =
178 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
179 // Vertex shader.
180 "#version 300 es\n"
181 "in highp vec4 a_position;\n"
182 "void main (void)\n"
183 "{\n"
184 " gl_Position = a_position;\n"
185 "}\n",
186
187 // Fragment shader.
188 "#version 300 es\n"
189 "uniform mediump vec4 u_color;\n"
190 "layout(location = 0) out mediump vec4 o_color;\n"
191 "void main (void)\n"
192 "{\n"
193 " o_color = u_color;\n"
194 "}\n"));
195
196 if (!m_visProgram->isOk())
197 {
198 log << *m_visProgram;
199 delete m_visProgram;
200 m_visProgram = DE_NULL;
201 TCU_FAIL("Compile failed");
202 }
203
204 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
205 }
206
deinit(void)207 void DepthStencilClearCase::deinit(void)
208 {
209 delete m_visProgram;
210 m_visProgram = DE_NULL;
211 }
212
iterate(void)213 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate(void)
214 {
215 const tcu::RenderTarget &renderTarget = m_context.getRenderTarget();
216 int width = renderTarget.getWidth();
217 int height = renderTarget.getHeight();
218 tcu::Surface result(width, height);
219 tcu::Surface reference(width, height);
220 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
221 vector<Clear> clears;
222
223 if ((m_testDepth && renderTarget.getDepthBits() == 0) || (m_testStencil && renderTarget.getStencilBits() == 0))
224 throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__);
225
226 generateClears(clears, deStringHash(getName()) ^ deInt32Hash(m_curIter));
227 renderGL(result, clears);
228 renderReference(reference, clears);
229
230 bool isLastIter = m_curIter + 1 == m_numIters;
231 bool isOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result,
232 threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
233
234 if (!isOk)
235 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
236
237 m_curIter += 1;
238 return isLastIter || !isOk ? STOP : CONTINUE;
239 }
240
generateClears(vector<Clear> & clears,uint32_t seed)241 void DepthStencilClearCase::generateClears(vector<Clear> &clears, uint32_t seed)
242 {
243 const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
244 int width = renderTarget.getWidth();
245 int height = renderTarget.getHeight();
246 de::Random rnd(seed);
247
248 clears.resize(m_numClears);
249
250 for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++)
251 {
252 if (m_testScissor)
253 {
254 int w = rnd.getInt(1, width);
255 int h = rnd.getInt(1, height);
256 int x = rnd.getInt(0, width - w);
257 int y = rnd.getInt(0, height - h);
258
259 clear->useScissor = true; // \todo [pyry] Should we randomize?
260 clear->scissor = tcu::IVec4(x, y, w, h);
261 }
262 else
263 clear->useScissor = false;
264
265 clear->clearDepth = rnd.getFloat(-0.2f, 1.2f);
266 clear->clearStencil = rnd.getUint32();
267
268 clear->depthMask = m_masked ? rnd.getBool() : true;
269 clear->stencilMask = m_masked ? rnd.getUint32() : 0xffffffffu;
270
271 if (m_testDepth && m_testStencil)
272 {
273 switch (rnd.getInt(0, 2))
274 {
275 case 0:
276 clear->clearMask = GL_DEPTH_BUFFER_BIT;
277 break;
278 case 1:
279 clear->clearMask = GL_STENCIL_BUFFER_BIT;
280 break;
281 case 2:
282 clear->clearMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
283 break;
284 }
285 }
286 else if (m_testDepth)
287 clear->clearMask = GL_DEPTH_BUFFER_BIT;
288 else
289 {
290 DE_ASSERT(m_testStencil);
291 clear->clearMask = GL_STENCIL_BUFFER_BIT;
292 }
293 }
294 }
295
renderGL(tcu::Surface & dst,const vector<Clear> & clears)296 void DepthStencilClearCase::renderGL(tcu::Surface &dst, const vector<Clear> &clears)
297 {
298 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
299 int colorLoc = gl.getUniformLocation(m_visProgram->getProgram(), "u_color");
300 int positionLoc = gl.getAttribLocation(m_visProgram->getProgram(), "a_position");
301 static const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
302
303 // Clear with default values.
304 gl.clearDepthf(1.0f);
305 gl.clearStencil(0);
306 gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
307 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
308
309 GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears");
310
311 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
312 {
313 if (clear->useScissor)
314 {
315 gl.enable(GL_SCISSOR_TEST);
316 gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w());
317 }
318
319 // Clear values.
320 gl.clearDepthf(clear->clearDepth);
321 gl.clearStencil(clear->clearStencil);
322
323 // Masks.
324 gl.depthMask(clear->depthMask ? GL_TRUE : GL_FALSE);
325 gl.stencilMask(clear->stencilMask);
326
327 // Execute clear.
328 gl.clear(clear->clearMask);
329
330 if (clear->useScissor)
331 gl.disable(GL_SCISSOR_TEST);
332 }
333
334 // Restore default masks.
335 gl.depthMask(GL_TRUE);
336 gl.stencilMask(0xffffffffu);
337
338 GLU_EXPECT_NO_ERROR(gl.getError(), "After clears");
339
340 gl.useProgram(m_visProgram->getProgram());
341 gl.enableVertexAttribArray(positionLoc);
342
343 // Visualize depth / stencil buffers.
344 if (m_testDepth)
345 {
346 int numSteps = DEPTH_STEPS;
347 float step = 2.0f / (float)numSteps;
348
349 gl.enable(GL_DEPTH_TEST);
350 gl.depthFunc(GL_LESS);
351 gl.depthMask(GL_FALSE);
352 gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
353
354 for (int ndx = 0; ndx < numSteps; ndx++)
355 {
356 float d = -1.0f + step * (float)ndx;
357 float c = (float)ndx / (float)(numSteps - 1);
358 float pos[] = {-1.0f, -1.0f, d, -1.0f, 1.0f, d, 1.0f, -1.0f, d, 1.0f, 1.0f, d};
359
360 gl.uniform4f(colorLoc, 0.0f, 0.0f, c, 1.0f);
361 gl.vertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]);
362 gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
363 }
364
365 gl.disable(GL_DEPTH_TEST);
366 gl.depthMask(GL_TRUE);
367
368 GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization");
369 }
370
371 if (m_testStencil)
372 {
373 int numSteps = STENCIL_STEPS;
374 int numValues = (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits
375 int step = numValues / numSteps;
376
377 gl.enable(GL_STENCIL_TEST);
378 gl.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
379 gl.colorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
380
381 static const float pos[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
382 gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]);
383
384 for (int ndx = 0; ndx < numSteps; ndx++)
385 {
386 int s = step * ndx;
387 float c = (float)ndx / (float)(numSteps - 1);
388
389 gl.stencilFunc(GL_LEQUAL, s, 0xffu);
390 gl.uniform4f(colorLoc, 0.0f, c, 0.0f, 1.0f);
391 gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
392 }
393
394 gl.disable(GL_STENCIL_TEST);
395
396 GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization");
397 }
398
399 // Restore color mask (changed by visualization).
400 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
401
402 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
403 }
404
renderReference(tcu::Surface & dst,const vector<Clear> & clears)405 void DepthStencilClearCase::renderReference(tcu::Surface &dst, const vector<Clear> &clears)
406 {
407 glu::RenderContext &renderCtx = TestCase::m_context.getRenderContext();
408 const tcu::RenderTarget &renderTarget = renderCtx.getRenderTarget();
409
410 // Clear surface to red.
411 tcu::clear(dst.getAccess(), tcu::RGBA::red().toVec());
412
413 if (m_testDepth)
414 {
415 // Simulated depth buffer span.
416 tcu::TextureLevel depthBufRow(getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1);
417 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess();
418
419 for (int y = 0; y < dst.getHeight(); y++)
420 {
421 // Clear to default value.
422 for (int x = 0; x < rowAccess.getWidth(); x++)
423 rowAccess.setPixel(Vec4(1.0f), x, 0);
424
425 // Execute clears.
426 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
427 {
428 // Clear / mask test.
429 if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask)
430 continue;
431
432 tcu::IVec4 clearRect =
433 clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
434
435 // Intersection test.
436 if (!de::inBounds(y, clearRect.y(), clearRect.y() + clearRect.w()))
437 continue;
438
439 for (int x = clearRect.x(); x < clearRect.x() + clearRect.z(); x++)
440 rowAccess.setPixDepth(de::clamp(clear->clearDepth, 0.0f, 1.0f), x, 0);
441 }
442
443 // Map to colors.
444 for (int x = 0; x < dst.getWidth(); x++)
445 {
446 float depth = rowAccess.getPixDepth(x, 0);
447 float step = deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS - 1);
448 tcu::RGBA oldColor = dst.getPixel(x, y);
449 tcu::RGBA newColor =
450 tcu::RGBA(oldColor.getRed(), oldColor.getGreen(),
451 deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha());
452
453 dst.setPixel(x, y, newColor);
454 }
455 }
456 }
457
458 if (m_testStencil)
459 {
460 // Simulated stencil buffer span.
461 int stencilBits = renderTarget.getStencilBits();
462 tcu::TextureLevel depthBufRow(getStencilFormat(stencilBits), dst.getWidth(), 1, 1);
463 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess();
464 uint32_t bufMask = (1u << stencilBits) - 1;
465
466 for (int y = 0; y < dst.getHeight(); y++)
467 {
468 // Clear to default value.
469 for (int x = 0; x < rowAccess.getWidth(); x++)
470 rowAccess.setPixel(tcu::UVec4(0), x, 0);
471
472 // Execute clears.
473 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++)
474 {
475 // Clear / mask test.
476 if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0)
477 continue;
478
479 tcu::IVec4 clearRect =
480 clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight());
481
482 // Intersection test.
483 if (!de::inBounds(y, clearRect.y(), clearRect.y() + clearRect.w()))
484 continue;
485
486 for (int x = clearRect.x(); x < clearRect.x() + clearRect.z(); x++)
487 {
488 uint32_t oldVal = rowAccess.getPixStencil(x, 0);
489 uint32_t newVal =
490 ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask;
491 rowAccess.setPixStencil(newVal, x, 0);
492 }
493 }
494
495 // Map to colors.
496 for (int x = 0; x < dst.getWidth(); x++)
497 {
498 uint32_t stencil = rowAccess.getPixStencil(x, 0);
499 float step =
500 (float)(stencil / ((1u << stencilBits) / (uint32_t)STENCIL_STEPS)) / (float)(STENCIL_STEPS - 1);
501 tcu::RGBA oldColor = dst.getPixel(x, y);
502 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255),
503 oldColor.getBlue(), oldColor.getAlpha());
504
505 dst.setPixel(x, y, newColor);
506 }
507 }
508 }
509 }
510
DepthStencilClearTests(Context & context)511 DepthStencilClearTests::DepthStencilClearTests(Context &context)
512 : TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests")
513 {
514 }
515
init(void)516 void DepthStencilClearTests::init(void)
517 {
518 // iters clears depth stencil scissor masked
519 addChild(new DepthStencilClearCase(m_context, "depth", "", 4, 2, true, false, false, false));
520 addChild(new DepthStencilClearCase(m_context, "depth_scissored", "", 4, 16, true, false, true, false));
521 addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked", "", 4, 16, true, false, true, true));
522
523 addChild(new DepthStencilClearCase(m_context, "stencil", "", 4, 2, false, true, false, false));
524 addChild(new DepthStencilClearCase(m_context, "stencil_masked", "", 4, 8, false, true, false, true));
525 addChild(new DepthStencilClearCase(m_context, "stencil_scissored", "", 4, 16, false, true, true, false));
526 addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked", "", 4, 16, false, true, true, true));
527
528 addChild(new DepthStencilClearCase(m_context, "depth_stencil", "", 4, 2, true, true, false, false));
529 addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked", "", 4, 8, true, true, false, true));
530 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored", "", 4, 16, true, true, true, false));
531 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked", "", 4, 16, true, true, true, true));
532 }
533
534 } // namespace Functional
535 } // namespace gles3
536 } // namespace deqp
537