xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderDiscardTests.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 Shader discard statement tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fShaderDiscardTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "gluTexture.hpp"
28 
29 #include <map>
30 #include <sstream>
31 #include <string>
32 
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 
36 using tcu::StringTemplate;
37 
38 using std::map;
39 using std::ostringstream;
40 using std::string;
41 
42 using namespace glu;
43 using namespace deqp::gls;
44 
45 namespace deqp
46 {
47 namespace gles2
48 {
49 namespace Functional
50 {
51 
52 enum CaseFlags
53 {
54     FLAG_USES_TEXTURES          = (1 << 0),
55     FLAG_REQUIRES_DYNAMIC_LOOPS = (1 << 1),
56 };
57 
58 class ShaderDiscardCase : public ShaderRenderCase
59 {
60 public:
61     ShaderDiscardCase(Context &context, const char *name, const char *description, const char *shaderSource,
62                       ShaderEvalFunc evalFunc, uint32_t flags);
63     virtual ~ShaderDiscardCase(void);
64 
65     void init(void);
66     void deinit(void);
67 
68     void setupUniforms(int programID, const tcu::Vec4 &constCoords);
69 
70 private:
71     const uint32_t m_flags;
72     glu::Texture2D *m_brickTexture;
73 };
74 
ShaderDiscardCase(Context & context,const char * name,const char * description,const char * shaderSource,ShaderEvalFunc evalFunc,uint32_t flags)75 ShaderDiscardCase::ShaderDiscardCase(Context &context, const char *name, const char *description,
76                                      const char *shaderSource, ShaderEvalFunc evalFunc, uint32_t flags)
77     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
78                        description, false, evalFunc)
79     , m_flags(flags)
80     , m_brickTexture(DE_NULL)
81 {
82     m_fragShaderSource = shaderSource;
83     m_vertShaderSource = "attribute highp   vec4 a_position;\n"
84                          "attribute highp   vec4 a_coords;\n"
85                          "varying   mediump vec4 v_color;\n"
86                          "varying   mediump vec4 v_coords;\n\n"
87                          "void main (void)\n"
88                          "{\n"
89                          "    gl_Position = a_position;\n"
90                          "    v_color = vec4(a_coords.xyz, 1.0);\n"
91                          "    v_coords = a_coords;\n"
92                          "}\n";
93 }
94 
~ShaderDiscardCase(void)95 ShaderDiscardCase::~ShaderDiscardCase(void)
96 {
97     delete m_brickTexture;
98 }
99 
init(void)100 void ShaderDiscardCase::init(void)
101 {
102     try
103     {
104         gls::ShaderRenderCase::init();
105     }
106     catch (const CompileFailed &)
107     {
108         if (m_flags & FLAG_REQUIRES_DYNAMIC_LOOPS)
109         {
110             const bool isSupported =
111                 m_isVertexCase ? m_ctxInfo.isVertexDynamicLoopSupported() : m_ctxInfo.isFragmentDynamicLoopSupported();
112             if (!isSupported)
113                 throw tcu::NotSupportedError("Dynamic loops not supported");
114         }
115 
116         throw;
117     }
118 
119     if (m_flags & FLAG_USES_TEXTURES)
120     {
121         m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png");
122         m_textures.push_back(TextureBinding(
123             m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
124                                          tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
125     }
126 }
127 
deinit(void)128 void ShaderDiscardCase::deinit(void)
129 {
130     gls::ShaderRenderCase::deinit();
131     delete m_brickTexture;
132     m_brickTexture = DE_NULL;
133 }
134 
setupUniforms(int programID,const tcu::Vec4 &)135 void ShaderDiscardCase::setupUniforms(int programID, const tcu::Vec4 &)
136 {
137     const glw::Functions &gl = m_renderCtx.getFunctions();
138     gl.uniform1i(gl.getUniformLocation(programID, "ut_brick"), 0);
139 }
140 
ShaderDiscardTests(Context & context)141 ShaderDiscardTests::ShaderDiscardTests(Context &context) : TestCaseGroup(context, "discard", "Discard statement tests")
142 {
143 }
144 
~ShaderDiscardTests(void)145 ShaderDiscardTests::~ShaderDiscardTests(void)
146 {
147 }
148 
149 enum DiscardMode
150 {
151     DISCARDMODE_ALWAYS = 0,
152     DISCARDMODE_NEVER,
153     DISCARDMODE_UNIFORM,
154     DISCARDMODE_DYNAMIC,
155     DISCARDMODE_TEXTURE,
156 
157     DISCARDMODE_LAST
158 };
159 
160 enum DiscardTemplate
161 {
162     DISCARDTEMPLATE_MAIN_BASIC = 0,
163     DISCARDTEMPLATE_FUNCTION_BASIC,
164     DISCARDTEMPLATE_MAIN_STATIC_LOOP,
165     DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP,
166     DISCARDTEMPLATE_FUNCTION_STATIC_LOOP,
167 
168     DISCARDTEMPLATE_LAST
169 };
170 
171 // Evaluation functions
evalDiscardAlways(ShaderEvalContext & c)172 inline void evalDiscardAlways(ShaderEvalContext &c)
173 {
174     c.discard();
175 }
evalDiscardNever(ShaderEvalContext & c)176 inline void evalDiscardNever(ShaderEvalContext &c)
177 {
178     c.color.xyz() = c.coords.swizzle(0, 1, 2);
179 }
evalDiscardDynamic(ShaderEvalContext & c)180 inline void evalDiscardDynamic(ShaderEvalContext &c)
181 {
182     c.color.xyz() = c.coords.swizzle(0, 1, 2);
183     if (c.coords.x() + c.coords.y() > 0.0f)
184         c.discard();
185 }
186 
evalDiscardTexture(ShaderEvalContext & c)187 inline void evalDiscardTexture(ShaderEvalContext &c)
188 {
189     c.color.xyz() = c.coords.swizzle(0, 1, 2);
190     if (c.texture2D(0, c.coords.swizzle(0, 1) * 0.25f + 0.5f).x() < 0.7f)
191         c.discard();
192 }
193 
getEvalFunc(DiscardMode mode)194 static ShaderEvalFunc getEvalFunc(DiscardMode mode)
195 {
196     switch (mode)
197     {
198     case DISCARDMODE_ALWAYS:
199         return evalDiscardAlways;
200     case DISCARDMODE_NEVER:
201         return evalDiscardNever;
202     case DISCARDMODE_UNIFORM:
203         return evalDiscardAlways;
204     case DISCARDMODE_DYNAMIC:
205         return evalDiscardDynamic;
206     case DISCARDMODE_TEXTURE:
207         return evalDiscardTexture;
208     default:
209         DE_ASSERT(false);
210         return evalDiscardAlways;
211     }
212 }
213 
getTemplate(DiscardTemplate variant)214 static const char *getTemplate(DiscardTemplate variant)
215 {
216     switch (variant)
217     {
218     case DISCARDTEMPLATE_MAIN_BASIC:
219         return "varying mediump vec4 v_color;\n"
220                "varying mediump vec4 v_coords;\n"
221                "uniform sampler2D    ut_brick;\n"
222                "uniform mediump int  ui_one;\n\n"
223                "void main (void)\n"
224                "{\n"
225                "    gl_FragColor = v_color;\n"
226                "    ${DISCARD};\n"
227                "}\n";
228 
229     case DISCARDTEMPLATE_FUNCTION_BASIC:
230         return "varying mediump vec4 v_color;\n"
231                "varying mediump vec4 v_coords;\n"
232                "uniform sampler2D    ut_brick;\n"
233                "uniform mediump int  ui_one;\n\n"
234                "void myfunc (void)\n"
235                "{\n"
236                "    ${DISCARD};\n"
237                "}\n\n"
238                "void main (void)\n"
239                "{\n"
240                "    gl_FragColor = v_color;\n"
241                "    myfunc();\n"
242                "}\n";
243 
244     case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
245         return "varying mediump vec4 v_color;\n"
246                "varying mediump vec4 v_coords;\n"
247                "uniform sampler2D    ut_brick;\n"
248                "uniform mediump int  ui_one;\n\n"
249                "void main (void)\n"
250                "{\n"
251                "    gl_FragColor = v_color;\n"
252                "    for (int i = 0; i < 2; i++)\n"
253                "    {\n"
254                "        if (i > 0)\n"
255                "            ${DISCARD};\n"
256                "    }\n"
257                "}\n";
258 
259     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
260         return "varying mediump vec4 v_color;\n"
261                "varying mediump vec4 v_coords;\n"
262                "uniform sampler2D    ut_brick;\n"
263                "uniform mediump int  ui_one;\n"
264                "uniform mediump int  ui_two;\n\n"
265                "void main (void)\n"
266                "{\n"
267                "    gl_FragColor = v_color;\n"
268                "    for (int i = 0; i < ui_two; i++)\n"
269                "    {\n"
270                "        if (i > 0)\n"
271                "            ${DISCARD};\n"
272                "    }\n"
273                "}\n";
274 
275     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
276         return "varying mediump vec4 v_color;\n"
277                "varying mediump vec4 v_coords;\n"
278                "uniform sampler2D    ut_brick;\n"
279                "uniform mediump int  ui_one;\n\n"
280                "void myfunc (void)\n"
281                "{\n"
282                "    for (int i = 0; i < 2; i++)\n"
283                "    {\n"
284                "        if (i > 0)\n"
285                "            ${DISCARD};\n"
286                "    }\n"
287                "}\n\n"
288                "void main (void)\n"
289                "{\n"
290                "    gl_FragColor = v_color;\n"
291                "    myfunc();\n"
292                "}\n";
293 
294     default:
295         DE_ASSERT(false);
296         return DE_NULL;
297     }
298 }
299 
getTemplateName(DiscardTemplate variant)300 static const char *getTemplateName(DiscardTemplate variant)
301 {
302     switch (variant)
303     {
304     case DISCARDTEMPLATE_MAIN_BASIC:
305         return "basic";
306     case DISCARDTEMPLATE_FUNCTION_BASIC:
307         return "function";
308     case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
309         return "static_loop";
310     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
311         return "dynamic_loop";
312     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
313         return "function_static_loop";
314     default:
315         DE_ASSERT(false);
316         return DE_NULL;
317     }
318 }
319 
getModeName(DiscardMode mode)320 static const char *getModeName(DiscardMode mode)
321 {
322     switch (mode)
323     {
324     case DISCARDMODE_ALWAYS:
325         return "always";
326     case DISCARDMODE_NEVER:
327         return "never";
328     case DISCARDMODE_UNIFORM:
329         return "uniform";
330     case DISCARDMODE_DYNAMIC:
331         return "dynamic";
332     case DISCARDMODE_TEXTURE:
333         return "texture";
334     default:
335         DE_ASSERT(false);
336         return DE_NULL;
337     }
338 }
339 
getTemplateDesc(DiscardTemplate variant)340 static const char *getTemplateDesc(DiscardTemplate variant)
341 {
342     switch (variant)
343     {
344     case DISCARDTEMPLATE_MAIN_BASIC:
345         return "main";
346     case DISCARDTEMPLATE_FUNCTION_BASIC:
347         return "function";
348     case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
349         return "static loop";
350     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
351         return "dynamic loop";
352     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
353         return "static loop in function";
354     default:
355         DE_ASSERT(false);
356         return DE_NULL;
357     }
358 }
359 
getModeDesc(DiscardMode mode)360 static const char *getModeDesc(DiscardMode mode)
361 {
362     switch (mode)
363     {
364     case DISCARDMODE_ALWAYS:
365         return "Always discard";
366     case DISCARDMODE_NEVER:
367         return "Never discard";
368     case DISCARDMODE_UNIFORM:
369         return "Discard based on uniform value";
370     case DISCARDMODE_DYNAMIC:
371         return "Discard based on varying values";
372     case DISCARDMODE_TEXTURE:
373         return "Discard based on texture value";
374     default:
375         DE_ASSERT(false);
376         return DE_NULL;
377     }
378 }
379 
makeDiscardCase(Context & context,DiscardTemplate tmpl,DiscardMode mode)380 ShaderDiscardCase *makeDiscardCase(Context &context, DiscardTemplate tmpl, DiscardMode mode)
381 {
382     StringTemplate shaderTemplate(getTemplate(tmpl));
383 
384     map<string, string> params;
385 
386     switch (mode)
387     {
388     case DISCARDMODE_ALWAYS:
389         params["DISCARD"] = "discard";
390         break;
391     case DISCARDMODE_NEVER:
392         params["DISCARD"] = "if (false) discard";
393         break;
394     case DISCARDMODE_UNIFORM:
395         params["DISCARD"] = "if (ui_one > 0) discard";
396         break;
397     case DISCARDMODE_DYNAMIC:
398         params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard";
399         break;
400     case DISCARDMODE_TEXTURE:
401         params["DISCARD"] = "if (texture2D(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard";
402         break;
403     default:
404         DE_ASSERT(false);
405         break;
406     }
407 
408     string name        = string(getTemplateName(tmpl)) + "_" + getModeName(mode);
409     string description = string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl);
410     uint32_t flags     = (mode == DISCARDMODE_TEXTURE ? FLAG_USES_TEXTURES : 0) |
411                      (tmpl == DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP ? FLAG_REQUIRES_DYNAMIC_LOOPS : 0);
412 
413     return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(),
414                                  getEvalFunc(mode), flags);
415 }
416 
init(void)417 void ShaderDiscardTests::init(void)
418 {
419     for (int tmpl = 0; tmpl < DISCARDTEMPLATE_LAST; tmpl++)
420         for (int mode = 0; mode < DISCARDMODE_LAST; mode++)
421             addChild(makeDiscardCase(m_context, (DiscardTemplate)tmpl, (DiscardMode)mode));
422 }
423 
424 } // namespace Functional
425 } // namespace gles2
426 } // namespace deqp
427