xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fDepthStencilClearTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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