xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fStencilTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 Stencil tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fStencilTests.hpp"
25 
26 #include "tcuSurface.hpp"
27 #include "tcuVector.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 
32 #include "sglrContextUtil.hpp"
33 #include "sglrGLContext.hpp"
34 #include "sglrReferenceContext.hpp"
35 
36 #include "deRandom.hpp"
37 #include "deMath.h"
38 #include "deString.h"
39 
40 #include <vector>
41 
42 #include "glwEnums.hpp"
43 #include "glwDefs.hpp"
44 
45 using std::vector;
46 using tcu::IVec2;
47 using tcu::IVec4;
48 using tcu::Vec3;
49 using namespace glw;
50 
51 namespace deqp
52 {
53 namespace gles3
54 {
55 namespace Functional
56 {
57 
58 class StencilShader : public sglr::ShaderProgram
59 {
60 public:
StencilShader(void)61     StencilShader(void)
62         : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
63                               << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
64                               << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
65                               << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
66                               << sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
67                               << sglr::pdec::VertexSource("#version 300 es\n"
68                                                           "in highp vec4 a_position;\n"
69                                                           "void main (void)\n"
70                                                           "{\n"
71                                                           "    gl_Position = a_position;\n"
72                                                           "}\n")
73                               << sglr::pdec::FragmentSource("#version 300 es\n"
74                                                             "uniform highp vec4 u_color;\n"
75                                                             "layout(location = 0) out mediump vec4 o_color;\n"
76                                                             "void main (void)\n"
77                                                             "{\n"
78                                                             "    o_color = u_color;\n"
79                                                             "}\n"))
80         , u_color(getUniformByName("u_color"))
81     {
82     }
83 
setColor(sglr::Context & ctx,uint32_t program,const tcu::Vec4 & color)84     void setColor(sglr::Context &ctx, uint32_t program, const tcu::Vec4 &color)
85     {
86         ctx.useProgram(program);
87         ctx.uniform4fv(ctx.getUniformLocation(program, "u_color"), 1, color.getPtr());
88     }
89 
90 private:
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const91     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
92     {
93         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
94         {
95             rr::VertexPacket &packet = *packets[packetNdx];
96 
97             packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
98         }
99     }
100 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const101     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
102                         const rr::FragmentShadingContext &context) const
103     {
104         const tcu::Vec4 color(u_color.value.f4);
105 
106         DE_UNREF(packets);
107 
108         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
109             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
110                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
111     }
112 
113     const sglr::UniformSlot &u_color;
114 };
115 
116 class StencilOp
117 {
118 public:
119     enum Type
120     {
121         TYPE_CLEAR_STENCIL = 0,
122         TYPE_CLEAR_DEPTH,
123         TYPE_QUAD,
124 
125         TYPE_LAST
126     };
127 
128     Type type;
129     GLenum stencilTest;
130     int stencil; //!< Ref for quad op, clear value for clears
131     uint32_t stencilMask;
132     GLenum depthTest;
133     float depth; //!< Quad depth or clear value
134     GLenum sFail;
135     GLenum dFail;
136     GLenum dPass;
137 
StencilOp(Type type_,GLenum stencilTest_=GL_ALWAYS,int stencil_=0,GLenum depthTest_=GL_ALWAYS,float depth_=1.0f,GLenum sFail_=GL_KEEP,GLenum dFail_=GL_KEEP,GLenum dPass_=GL_KEEP)138     StencilOp(Type type_, GLenum stencilTest_ = GL_ALWAYS, int stencil_ = 0, GLenum depthTest_ = GL_ALWAYS,
139               float depth_ = 1.0f, GLenum sFail_ = GL_KEEP, GLenum dFail_ = GL_KEEP, GLenum dPass_ = GL_KEEP)
140         : type(type_)
141         , stencilTest(stencilTest_)
142         , stencil(stencil_)
143         , stencilMask(0xffffffffu)
144         , depthTest(depthTest_)
145         , depth(depth_)
146         , sFail(sFail_)
147         , dFail(dFail_)
148         , dPass(dPass_)
149     {
150     }
151 
clearStencil(int stencil)152     static StencilOp clearStencil(int stencil)
153     {
154         StencilOp op(TYPE_CLEAR_STENCIL);
155         op.stencil = stencil;
156         return op;
157     }
158 
clearDepth(float depth)159     static StencilOp clearDepth(float depth)
160     {
161         StencilOp op(TYPE_CLEAR_DEPTH);
162         op.depth = depth;
163         return op;
164     }
165 
quad(GLenum stencilTest,int stencil,GLenum depthTest,float depth,GLenum sFail,GLenum dFail,GLenum dPass)166     static StencilOp quad(GLenum stencilTest, int stencil, GLenum depthTest, float depth, GLenum sFail, GLenum dFail,
167                           GLenum dPass)
168     {
169         return StencilOp(TYPE_QUAD, stencilTest, stencil, depthTest, depth, sFail, dFail, dPass);
170     }
171 };
172 
173 class StencilCase : public TestCase
174 {
175 public:
176     StencilCase(Context &context, const char *name, const char *description);
177     virtual ~StencilCase(void);
178 
179     void init(void);
180     void deinit(void);
181     IterateResult iterate(void);
182 
183     virtual void genOps(vector<StencilOp> &dst, int stencilBits, int depthBits, int targetStencil) = DE_NULL;
184 
185 private:
186     void executeOps(sglr::Context &context, const IVec4 &cell, const vector<StencilOp> &ops);
187     void visualizeStencil(sglr::Context &context, int stencilBits, int stencilStep);
188 
189     StencilShader m_shader;
190     uint32_t m_shaderID;
191 };
192 
StencilCase(Context & context,const char * name,const char * description)193 StencilCase::StencilCase(Context &context, const char *name, const char *description)
194     : TestCase(context, name, description)
195     , m_shaderID(0)
196 {
197 }
198 
~StencilCase(void)199 StencilCase::~StencilCase(void)
200 {
201 }
202 
init(void)203 void StencilCase::init(void)
204 {
205 }
206 
deinit(void)207 void StencilCase::deinit(void)
208 {
209 }
210 
executeOps(sglr::Context & context,const IVec4 & cell,const vector<StencilOp> & ops)211 void StencilCase::executeOps(sglr::Context &context, const IVec4 &cell, const vector<StencilOp> &ops)
212 {
213     // For quadOps
214     float x0 = 2.0f * ((float)cell.x() / (float)context.getWidth()) - 1.0f;
215     float y0 = 2.0f * ((float)cell.y() / (float)context.getHeight()) - 1.0f;
216     float x1 = x0 + 2.0f * ((float)cell.z() / (float)context.getWidth());
217     float y1 = y0 + 2.0f * ((float)cell.w() / (float)context.getHeight());
218 
219     m_shader.setColor(context, m_shaderID, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
220 
221     for (vector<StencilOp>::const_iterator i = ops.begin(); i != ops.end(); i++)
222     {
223         const StencilOp &op = *i;
224 
225         switch (op.type)
226         {
227         case StencilOp::TYPE_CLEAR_DEPTH:
228             context.enable(GL_SCISSOR_TEST);
229             context.scissor(cell.x(), cell.y(), cell.z(), cell.w());
230             context.clearDepthf(op.depth);
231             context.clear(GL_DEPTH_BUFFER_BIT);
232             context.disable(GL_SCISSOR_TEST);
233             break;
234 
235         case StencilOp::TYPE_CLEAR_STENCIL:
236             context.enable(GL_SCISSOR_TEST);
237             context.scissor(cell.x(), cell.y(), cell.z(), cell.w());
238             context.clearStencil(op.stencil);
239             context.clear(GL_STENCIL_BUFFER_BIT);
240             context.disable(GL_SCISSOR_TEST);
241             break;
242 
243         case StencilOp::TYPE_QUAD:
244             context.enable(GL_DEPTH_TEST);
245             context.enable(GL_STENCIL_TEST);
246             context.depthFunc(op.depthTest);
247             context.stencilFunc(op.stencilTest, op.stencil, op.stencilMask);
248             context.stencilOp(op.sFail, op.dFail, op.dPass);
249             sglr::drawQuad(context, m_shaderID, Vec3(x0, y0, op.depth), Vec3(x1, y1, op.depth));
250             context.disable(GL_STENCIL_TEST);
251             context.disable(GL_DEPTH_TEST);
252             break;
253 
254         default:
255             DE_ASSERT(false);
256         }
257     }
258 }
259 
visualizeStencil(sglr::Context & context,int stencilBits,int stencilStep)260 void StencilCase::visualizeStencil(sglr::Context &context, int stencilBits, int stencilStep)
261 {
262     int endVal           = 1 << stencilBits;
263     int numStencilValues = endVal / stencilStep + 1;
264 
265     context.enable(GL_STENCIL_TEST);
266     context.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
267 
268     for (int ndx = 0; ndx < numStencilValues; ndx++)
269     {
270         int value      = deMin32(ndx * stencilStep, endVal - 1);
271         float colorMix = (float)value / (float)de::max(1, endVal - 1);
272         tcu::Vec4 color(0.0f, 1.0f - colorMix, colorMix, 1.0f);
273 
274         m_shader.setColor(context, m_shaderID, color);
275         context.stencilFunc(GL_EQUAL, value, 0xffffffffu);
276         sglr::drawQuad(context, m_shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
277     }
278 }
279 
iterate(void)280 TestCase::IterateResult StencilCase::iterate(void)
281 {
282     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
283     int depthBits                         = renderTarget.getDepthBits();
284     int stencilBits                       = renderTarget.getStencilBits();
285 
286     int stencilStep      = stencilBits == 8 ? 8 : 1;
287     int numStencilValues = (1 << stencilBits) / stencilStep + 1;
288 
289     int gridSize = (int)deFloatCeil(deFloatSqrt((float)(numStencilValues + 2)));
290 
291     int width  = deMin32(128, renderTarget.getWidth());
292     int height = deMin32(128, renderTarget.getHeight());
293 
294     tcu::TestLog &log = m_testCtx.getLog();
295     de::Random rnd(deStringHash(m_name.c_str()));
296     int viewportX  = rnd.getInt(0, renderTarget.getWidth() - width);
297     int viewportY  = rnd.getInt(0, renderTarget.getHeight() - height);
298     IVec4 viewport = IVec4(viewportX, viewportY, width, height);
299 
300     tcu::Surface gles2Frame(width, height);
301     tcu::Surface refFrame(width, height);
302     GLenum gles2Error;
303 
304     const char *failReason = DE_NULL;
305 
306     // Get ops for stencil values
307     vector<vector<StencilOp>> ops(numStencilValues + 2);
308     {
309         // Values from 0 to max
310         for (int ndx = 0; ndx < numStencilValues; ndx++)
311             genOps(ops[ndx], stencilBits, depthBits, deMin32(ndx * stencilStep, (1 << stencilBits) - 1));
312 
313         // -1 and max+1
314         genOps(ops[numStencilValues + 0], stencilBits, depthBits, 1 << stencilBits);
315         genOps(ops[numStencilValues + 1], stencilBits, depthBits, -1);
316     }
317 
318     // Compute cells: (x, y, w, h)
319     vector<IVec4> cells;
320     int cellWidth  = width / gridSize;
321     int cellHeight = height / gridSize;
322     for (int y = 0; y < gridSize; y++)
323         for (int x = 0; x < gridSize; x++)
324             cells.push_back(IVec4(x * cellWidth, y * cellHeight, cellWidth, cellHeight));
325 
326     DE_ASSERT(ops.size() <= cells.size());
327 
328     // Execute for gles3 context
329     {
330         sglr::GLContext context(m_context.getRenderContext(), log, 0 /* don't log calls or program */, viewport);
331 
332         m_shaderID = context.createProgram(&m_shader);
333 
334         context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
335         context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
336 
337         for (int ndx = 0; ndx < (int)ops.size(); ndx++)
338             executeOps(context, cells[ndx], ops[ndx]);
339 
340         visualizeStencil(context, stencilBits, stencilStep);
341 
342         gles2Error = context.getError();
343         context.readPixels(gles2Frame, 0, 0, width, height);
344     }
345 
346     // Execute for reference context
347     {
348         sglr::ReferenceContextBuffers buffers(
349             tcu::PixelFormat(8, 8, 8, renderTarget.getPixelFormat().alphaBits ? 8 : 0), renderTarget.getDepthBits(),
350             renderTarget.getStencilBits(), width, height);
351         sglr::ReferenceContext context(sglr::ReferenceContextLimits(m_context.getRenderContext()),
352                                        buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
353 
354         m_shaderID = context.createProgram(&m_shader);
355 
356         context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
357         context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
358 
359         for (int ndx = 0; ndx < (int)ops.size(); ndx++)
360             executeOps(context, cells[ndx], ops[ndx]);
361 
362         visualizeStencil(context, stencilBits, stencilStep);
363 
364         context.readPixels(refFrame, 0, 0, width, height);
365     }
366 
367     // Check error
368     bool errorCodeOk = (gles2Error == GL_NO_ERROR);
369     if (!errorCodeOk && !failReason)
370         failReason = "Got unexpected error";
371 
372     // Compare images
373     const float threshold = 0.02f;
374     bool imagesOk         = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles2Frame,
375                                               threshold, tcu::COMPARE_LOG_RESULT);
376 
377     if (!imagesOk && !failReason)
378         failReason = "Image comparison failed";
379 
380     // Store test result
381     bool isOk = errorCodeOk && imagesOk;
382     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : failReason);
383 
384     return STOP;
385 }
386 
StencilTests(Context & context)387 StencilTests::StencilTests(Context &context) : TestCaseGroup(context, "stencil", "Stencil Tests")
388 {
389 }
390 
~StencilTests(void)391 StencilTests::~StencilTests(void)
392 {
393 }
394 
395 typedef void (*GenStencilOpsFunc)(vector<StencilOp> &dst, int stencilBits, int depthBits, int targetStencil);
396 
397 class SimpleStencilCase : public StencilCase
398 {
399 public:
SimpleStencilCase(Context & context,const char * name,const char * description,GenStencilOpsFunc genOpsFunc)400     SimpleStencilCase(Context &context, const char *name, const char *description, GenStencilOpsFunc genOpsFunc)
401         : StencilCase(context, name, description)
402         , m_genOps(genOpsFunc)
403     {
404     }
405 
genOps(vector<StencilOp> & dst,int stencilBits,int depthBits,int targetStencil)406     void genOps(vector<StencilOp> &dst, int stencilBits, int depthBits, int targetStencil)
407     {
408         m_genOps(dst, stencilBits, depthBits, targetStencil);
409     }
410 
411 private:
412     GenStencilOpsFunc m_genOps;
413 };
414 
init(void)415 void StencilTests::init(void)
416 {
417 #define STENCIL_CASE(NAME, DESCRIPTION, GEN_OPS_BODY)                                                     \
418     do                                                                                                    \
419     {                                                                                                     \
420         struct Gen_##NAME                                                                                 \
421         {                                                                                                 \
422             static void genOps(vector<StencilOp> &dst, int stencilBits, int depthBits, int targetStencil) \
423             {                                                                                             \
424                 DE_UNREF(stencilBits &&depthBits);                                                        \
425                 GEN_OPS_BODY                                                                              \
426             }                                                                                             \
427         };                                                                                                \
428         addChild(new SimpleStencilCase(m_context, #NAME, DESCRIPTION, Gen_##NAME::genOps));               \
429     } while (false);
430 
431     STENCIL_CASE(clear, "Stencil clear", {
432         // \note Unused bits are set to 1, clear should mask them out
433         int mask = (1 << stencilBits) - 1;
434         dst.push_back(StencilOp::clearStencil(targetStencil | ~mask));
435     })
436 
437     // Replace in different points
438     STENCIL_CASE(stencil_fail_replace, "Set stencil on stencil fail", {
439         dst.push_back(StencilOp::quad(GL_NEVER, targetStencil, GL_ALWAYS, 0.0f, GL_REPLACE, GL_KEEP, GL_KEEP));
440     })
441     STENCIL_CASE(depth_fail_replace, "Set stencil on depth fail", {
442         dst.push_back(StencilOp::clearDepth(0.0f));
443         dst.push_back(StencilOp::quad(GL_ALWAYS, targetStencil, GL_LESS, 0.5f, GL_KEEP, GL_REPLACE, GL_KEEP));
444     })
445     STENCIL_CASE(depth_pass_replace, "Set stencil on depth pass", {
446         dst.push_back(StencilOp::quad(GL_ALWAYS, targetStencil, GL_LESS, 0.0f, GL_KEEP, GL_KEEP, GL_REPLACE));
447     })
448 
449     // Increment, decrement
450     STENCIL_CASE(incr_stencil_fail, "Increment on stencil fail", {
451         if (targetStencil > 0)
452         {
453             dst.push_back(StencilOp::clearStencil(targetStencil - 1));
454             dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_INCR, GL_KEEP, GL_KEEP));
455         }
456         else
457             dst.push_back(StencilOp::clearStencil(targetStencil));
458     })
459     STENCIL_CASE(decr_stencil_fail, "Decrement on stencil fail", {
460         int maxStencil = (1 << stencilBits) - 1;
461         if (targetStencil < maxStencil)
462         {
463             dst.push_back(StencilOp::clearStencil(targetStencil + 1));
464             dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_DECR, GL_KEEP, GL_KEEP));
465         }
466         else
467             dst.push_back(StencilOp::clearStencil(targetStencil));
468     })
469     STENCIL_CASE(incr_wrap_stencil_fail, "Increment (wrap) on stencil fail", {
470         int maxStencil = (1 << stencilBits) - 1;
471         dst.push_back(StencilOp::clearStencil((targetStencil - 1) & maxStencil));
472         dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_INCR_WRAP, GL_KEEP, GL_KEEP));
473     })
474     STENCIL_CASE(decr_wrap_stencil_fail, "Decrement (wrap) on stencil fail", {
475         int maxStencil = (1 << stencilBits) - 1;
476         dst.push_back(StencilOp::clearStencil((targetStencil + 1) & maxStencil));
477         dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_DECR_WRAP, GL_KEEP, GL_KEEP));
478     })
479 
480     // Zero, Invert
481     STENCIL_CASE(zero_stencil_fail, "Zero on stencil fail", {
482         dst.push_back(StencilOp::clearStencil(targetStencil));
483         dst.push_back(StencilOp::quad(GL_NOTEQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_ZERO, GL_KEEP, GL_KEEP));
484         dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_REPLACE, GL_KEEP, GL_KEEP));
485     })
486     STENCIL_CASE(invert_stencil_fail, "Invert on stencil fail", {
487         int mask = (1 << stencilBits) - 1;
488         dst.push_back(StencilOp::clearStencil((~targetStencil) & mask));
489         dst.push_back(StencilOp::quad(GL_EQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_INVERT, GL_KEEP, GL_KEEP));
490     })
491 
492     // Comparison modes
493     STENCIL_CASE(cmp_equal, "Equality comparison", {
494         int mask = (1 << stencilBits) - 1;
495         int inv  = (~targetStencil) & mask;
496         dst.push_back(StencilOp::clearStencil(inv));
497         dst.push_back(StencilOp::quad(GL_EQUAL, inv, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INVERT));
498         dst.push_back(StencilOp::quad(GL_EQUAL, inv, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INVERT));
499     })
500     STENCIL_CASE(cmp_not_equal, "Equality comparison", {
501         int mask = (1 << stencilBits) - 1;
502         int inv  = (~targetStencil) & mask;
503         dst.push_back(StencilOp::clearStencil(inv));
504         dst.push_back(StencilOp::quad(GL_NOTEQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INVERT));
505         dst.push_back(StencilOp::quad(GL_NOTEQUAL, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INVERT));
506     })
507     STENCIL_CASE(cmp_less_than, "Less than comparison", {
508         int maxStencil = (1 << stencilBits) - 1;
509         if (targetStencil < maxStencil)
510         {
511             dst.push_back(StencilOp::clearStencil(targetStencil + 1));
512             dst.push_back(StencilOp::quad(GL_LESS, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_DECR));
513             dst.push_back(StencilOp::quad(GL_LESS, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_DECR));
514         }
515         else
516             dst.push_back(StencilOp::clearStencil(targetStencil));
517     })
518     STENCIL_CASE(cmp_less_or_equal, "Less or equal comparison", {
519         int maxStencil = (1 << stencilBits) - 1;
520         if (targetStencil < maxStencil)
521         {
522             dst.push_back(StencilOp::clearStencil(targetStencil + 1));
523             dst.push_back(StencilOp::quad(GL_LEQUAL, targetStencil + 1, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_DECR));
524             dst.push_back(StencilOp::quad(GL_LEQUAL, targetStencil + 1, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_DECR));
525         }
526         else
527             dst.push_back(StencilOp::clearStencil(targetStencil));
528     })
529     STENCIL_CASE(cmp_greater_than, "Greater than comparison", {
530         if (targetStencil > 0)
531         {
532             dst.push_back(StencilOp::clearStencil(targetStencil - 1));
533             dst.push_back(StencilOp::quad(GL_GREATER, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INCR));
534             dst.push_back(StencilOp::quad(GL_GREATER, targetStencil, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INCR));
535         }
536         else
537             dst.push_back(StencilOp::clearStencil(targetStencil));
538     })
539     STENCIL_CASE(cmp_greater_or_equal, "Greater or equal comparison", {
540         if (targetStencil > 0)
541         {
542             dst.push_back(StencilOp::clearStencil(targetStencil - 1));
543             dst.push_back(StencilOp::quad(GL_GEQUAL, targetStencil - 1, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INCR));
544             dst.push_back(StencilOp::quad(GL_GEQUAL, targetStencil - 1, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INCR));
545         }
546         else
547             dst.push_back(StencilOp::clearStencil(targetStencil));
548     })
549     STENCIL_CASE(cmp_mask_equal, "Equality comparison with mask", {
550         int valMask = (1 << stencilBits) - 1;
551         int mask    = (1 << 7) | (1 << 5) | (1 << 3) | (1 << 1);
552         dst.push_back(StencilOp::clearStencil(~targetStencil));
553         StencilOp op =
554             StencilOp::quad(GL_EQUAL, (~targetStencil | ~mask) & valMask, GL_ALWAYS, 0.0f, GL_KEEP, GL_KEEP, GL_INVERT);
555         op.stencilMask = mask;
556         dst.push_back(op);
557     })
558 }
559 
560 } // namespace Functional
561 } // namespace gles3
562 } // namespace deqp
563