xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderReturnTests.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 Shader return statement tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fShaderReturnTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "tcuStringTemplate.hpp"
27 
28 #include <map>
29 #include <sstream>
30 #include <string>
31 
32 using tcu::StringTemplate;
33 
34 using std::map;
35 using std::ostringstream;
36 using std::string;
37 
38 using namespace glu;
39 using namespace deqp::gls;
40 
41 namespace deqp
42 {
43 namespace gles3
44 {
45 namespace Functional
46 {
47 
48 enum ReturnMode
49 {
50     RETURNMODE_ALWAYS = 0,
51     RETURNMODE_NEVER,
52     RETURNMODE_DYNAMIC,
53 
54     RETURNMODE_LAST
55 };
56 
57 // Evaluation functions
evalReturnAlways(ShaderEvalContext & c)58 inline void evalReturnAlways(ShaderEvalContext &c)
59 {
60     c.color.xyz() = c.coords.swizzle(0, 1, 2);
61 }
evalReturnNever(ShaderEvalContext & c)62 inline void evalReturnNever(ShaderEvalContext &c)
63 {
64     c.color.xyz() = c.coords.swizzle(3, 2, 1);
65 }
evalReturnDynamic(ShaderEvalContext & c)66 inline void evalReturnDynamic(ShaderEvalContext &c)
67 {
68     c.color.xyz() = (c.coords.x() + c.coords.y() >= 0.0f) ? c.coords.swizzle(0, 1, 2) : c.coords.swizzle(3, 2, 1);
69 }
70 
getEvalFunc(ReturnMode mode)71 static ShaderEvalFunc getEvalFunc(ReturnMode mode)
72 {
73     switch (mode)
74     {
75     case RETURNMODE_ALWAYS:
76         return evalReturnAlways;
77     case RETURNMODE_NEVER:
78         return evalReturnNever;
79     case RETURNMODE_DYNAMIC:
80         return evalReturnDynamic;
81     default:
82         DE_ASSERT(false);
83         return (ShaderEvalFunc)DE_NULL;
84     }
85 }
86 
87 class ShaderReturnCase : public ShaderRenderCase
88 {
89 public:
90     ShaderReturnCase(Context &context, const char *name, const char *description, bool isVertexCase,
91                      const char *shaderSource, ShaderEvalFunc evalFunc);
92     virtual ~ShaderReturnCase(void);
93 };
94 
ShaderReturnCase(Context & context,const char * name,const char * description,bool isVertexCase,const char * shaderSource,ShaderEvalFunc evalFunc)95 ShaderReturnCase::ShaderReturnCase(Context &context, const char *name, const char *description, bool isVertexCase,
96                                    const char *shaderSource, ShaderEvalFunc evalFunc)
97     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
98                        description, isVertexCase, evalFunc)
99 {
100     if (isVertexCase)
101     {
102         m_vertShaderSource = shaderSource;
103         m_fragShaderSource = "#version 300 es\n"
104                              "in mediump vec4 v_color;\n"
105                              "layout(location = 0) out mediump vec4 o_color;\n\n"
106                              "void main (void)\n"
107                              "{\n"
108                              "    o_color = v_color;\n"
109                              "}\n";
110     }
111     else
112     {
113         m_fragShaderSource = shaderSource;
114         m_vertShaderSource = "#version 300 es\n"
115                              "in  highp   vec4 a_position;\n"
116                              "in  highp   vec4 a_coords;\n"
117                              "out mediump vec4 v_coords;\n\n"
118                              "void main (void)\n"
119                              "{\n"
120                              "    gl_Position = a_position;\n"
121                              "    v_coords = a_coords;\n"
122                              "}\n";
123     }
124 }
125 
~ShaderReturnCase(void)126 ShaderReturnCase::~ShaderReturnCase(void)
127 {
128 }
129 
ShaderReturnTests(Context & context)130 ShaderReturnTests::ShaderReturnTests(Context &context) : TestCaseGroup(context, "return", "Return Statement Tests")
131 {
132 }
133 
~ShaderReturnTests(void)134 ShaderReturnTests::~ShaderReturnTests(void)
135 {
136 }
137 
makeConditionalReturnInFuncCase(Context & context,const char * name,const char * description,ReturnMode returnMode,bool isVertex)138 ShaderReturnCase *makeConditionalReturnInFuncCase(Context &context, const char *name, const char *description,
139                                                   ReturnMode returnMode, bool isVertex)
140 {
141     // Template
142     StringTemplate tmpl("#version 300 es\n"
143                         "in ${COORDPREC} vec4 ${COORDS};\n"
144                         "${EXTRADECL}\n"
145                         "${COORDPREC} vec4 getColor (void)\n"
146                         "{\n"
147                         "    if (${RETURNCOND})\n"
148                         "        return vec4(${COORDS}.xyz, 1.0);\n"
149                         "    return vec4(${COORDS}.wzy, 1.0);\n"
150                         "}\n\n"
151                         "void main (void)\n"
152                         "{\n"
153                         "${POSITIONWRITE}"
154                         "    ${OUTPUT} = getColor();\n"
155                         "}\n");
156 
157     const char *coords = isVertex ? "a_coords" : "v_coords";
158 
159     map<string, string> params;
160 
161     params["COORDPREC"]     = isVertex ? "highp" : "mediump";
162     params["OUTPUT"]        = isVertex ? "v_color" : "o_color";
163     params["COORDS"]        = coords;
164     params["EXTRADECL"]     = isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" :
165                                          "layout(location = 0) out mediump vec4 o_color;\n";
166     params["POSITIONWRITE"] = isVertex ? "    gl_Position = a_position;\n" : "";
167 
168     switch (returnMode)
169     {
170     case RETURNMODE_ALWAYS:
171         params["RETURNCOND"] = "true";
172         break;
173     case RETURNMODE_NEVER:
174         params["RETURNCOND"] = "false";
175         break;
176     case RETURNMODE_DYNAMIC:
177         params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";
178         break;
179     default:
180         DE_ASSERT(false);
181     }
182 
183     return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(),
184                                 getEvalFunc(returnMode));
185 }
186 
makeOutputWriteReturnCase(Context & context,const char * name,const char * description,bool inFunction,ReturnMode returnMode,bool isVertex)187 ShaderReturnCase *makeOutputWriteReturnCase(Context &context, const char *name, const char *description,
188                                             bool inFunction, ReturnMode returnMode, bool isVertex)
189 {
190     // Template
191     StringTemplate tmpl(inFunction ? "#version 300 es\n"
192                                      "in ${COORDPREC} vec4 ${COORDS};\n"
193                                      "${EXTRADECL}\n"
194                                      "void myfunc (void)\n"
195                                      "{\n"
196                                      "    ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
197                                      "    if (${RETURNCOND})\n"
198                                      "        return;\n"
199                                      "    ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
200                                      "}\n\n"
201                                      "void main (void)\n"
202                                      "{\n"
203                                      "${POSITIONWRITE}"
204                                      "    myfunc();\n"
205                                      "}\n" :
206                                      "#version 300 es\n"
207                                      "in ${COORDPREC} vec4 ${COORDS};\n"
208                                      "uniform mediump int ui_one;\n"
209                                      "${EXTRADECL}\n"
210                                      "void main ()\n"
211                                      "{\n"
212                                      "${POSITIONWRITE}"
213                                      "    ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
214                                      "    if (${RETURNCOND})\n"
215                                      "        return;\n"
216                                      "    ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
217                                      "}\n");
218 
219     const char *coords = isVertex ? "a_coords" : "v_coords";
220 
221     map<string, string> params;
222 
223     params["COORDPREC"]     = isVertex ? "highp" : "mediump";
224     params["COORDS"]        = coords;
225     params["OUTPUT"]        = isVertex ? "v_color" : "o_color";
226     params["EXTRADECL"]     = isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" :
227                                          "layout(location = 0) out mediump vec4 o_color;\n";
228     params["POSITIONWRITE"] = isVertex ? "    gl_Position = a_position;\n" : "";
229 
230     switch (returnMode)
231     {
232     case RETURNMODE_ALWAYS:
233         params["RETURNCOND"] = "true";
234         break;
235     case RETURNMODE_NEVER:
236         params["RETURNCOND"] = "false";
237         break;
238     case RETURNMODE_DYNAMIC:
239         params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";
240         break;
241     default:
242         DE_ASSERT(false);
243     }
244 
245     return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(),
246                                 getEvalFunc(returnMode));
247 }
248 
makeReturnInLoopCase(Context & context,const char * name,const char * description,bool isDynamicLoop,ReturnMode returnMode,bool isVertex)249 ShaderReturnCase *makeReturnInLoopCase(Context &context, const char *name, const char *description, bool isDynamicLoop,
250                                        ReturnMode returnMode, bool isVertex)
251 {
252     // Template
253     StringTemplate tmpl("#version 300 es\n"
254                         "in ${COORDPREC} vec4 ${COORDS};\n"
255                         "uniform mediump int ui_one;\n"
256                         "${EXTRADECL}\n"
257                         "${COORDPREC} vec4 getCoords (void)\n"
258                         "{\n"
259                         "    ${COORDPREC} vec4 coords = ${COORDS};\n"
260                         "    for (int i = 0; i < ${ITERLIMIT}; i++)\n"
261                         "    {\n"
262                         "        if (${RETURNCOND})\n"
263                         "            return coords;\n"
264                         "        coords = coords.wzyx;\n"
265                         "    }\n"
266                         "    return coords;\n"
267                         "}\n\n"
268                         "void main (void)\n"
269                         "{\n"
270                         "${POSITIONWRITE}"
271                         "    ${OUTPUT} = vec4(getCoords().xyz, 1.0);\n"
272                         "}\n");
273 
274     const char *coords = isVertex ? "a_coords" : "v_coords";
275 
276     map<string, string> params;
277 
278     params["COORDPREC"]     = isVertex ? "highp" : "mediump";
279     params["OUTPUT"]        = isVertex ? "v_color" : "o_color";
280     params["COORDS"]        = coords;
281     params["EXTRADECL"]     = isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" :
282                                          "layout(location = 0) out mediump vec4 o_color;\n";
283     params["POSITIONWRITE"] = isVertex ? "    gl_Position = a_position;\n" : "";
284     params["ITERLIMIT"]     = isDynamicLoop ? "ui_one" : "1";
285 
286     switch (returnMode)
287     {
288     case RETURNMODE_ALWAYS:
289         params["RETURNCOND"] = "true";
290         break;
291     case RETURNMODE_NEVER:
292         params["RETURNCOND"] = "false";
293         break;
294     case RETURNMODE_DYNAMIC:
295         params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";
296         break;
297     default:
298         DE_ASSERT(false);
299     }
300 
301     return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(),
302                                 getEvalFunc(returnMode));
303 }
304 
getReturnModeName(ReturnMode mode)305 static const char *getReturnModeName(ReturnMode mode)
306 {
307     switch (mode)
308     {
309     case RETURNMODE_ALWAYS:
310         return "always";
311     case RETURNMODE_NEVER:
312         return "never";
313     case RETURNMODE_DYNAMIC:
314         return "dynamic";
315     default:
316         DE_ASSERT(false);
317         return DE_NULL;
318     }
319 }
320 
getReturnModeDesc(ReturnMode mode)321 static const char *getReturnModeDesc(ReturnMode mode)
322 {
323     switch (mode)
324     {
325     case RETURNMODE_ALWAYS:
326         return "Always return";
327     case RETURNMODE_NEVER:
328         return "Never return";
329     case RETURNMODE_DYNAMIC:
330         return "Return based on coords";
331     default:
332         DE_ASSERT(false);
333         return DE_NULL;
334     }
335 }
336 
init(void)337 void ShaderReturnTests::init(void)
338 {
339     // Single return statement in function.
340     addChild(new ShaderReturnCase(m_context, "single_return_vertex", "Single return statement in function", true,
341                                   "#version 300 es\n"
342                                   "in highp vec4 a_position;\n"
343                                   "in highp vec4 a_coords;\n"
344                                   "out highp vec4 v_color;\n\n"
345                                   "vec4 getColor (void)\n"
346                                   "{\n"
347                                   "    return vec4(a_coords.xyz, 1.0);\n"
348                                   "}\n\n"
349                                   "void main (void)\n"
350                                   "{\n"
351                                   "    gl_Position = a_position;\n"
352                                   "    v_color = getColor();\n"
353                                   "}\n",
354                                   evalReturnAlways));
355     addChild(new ShaderReturnCase(m_context, "single_return_fragment", "Single return statement in function", false,
356                                   "#version 300 es\n"
357                                   "in mediump vec4 v_coords;\n"
358                                   "layout(location = 0) out mediump vec4 o_color;\n"
359                                   "mediump vec4 getColor (void)\n"
360                                   "{\n"
361                                   "    return vec4(v_coords.xyz, 1.0);\n"
362                                   "}\n\n"
363                                   "void main (void)\n"
364                                   "{\n"
365                                   "    o_color = getColor();\n"
366                                   "}\n",
367                                   evalReturnAlways));
368 
369     // Conditional return statement in function.
370     for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
371     {
372         for (int isFragment = 0; isFragment < 2; isFragment++)
373         {
374             string name = string("conditional_return_") + getReturnModeName((ReturnMode)returnMode) +
375                           (isFragment ? "_fragment" : "_vertex");
376             string description = string(getReturnModeDesc((ReturnMode)returnMode)) + " in function";
377             addChild(makeConditionalReturnInFuncCase(m_context, name.c_str(), description.c_str(),
378                                                      (ReturnMode)returnMode, isFragment == 0));
379         }
380     }
381 
382     // Unconditional double return in function.
383     addChild(new ShaderReturnCase(m_context, "double_return_vertex", "Unconditional double return in function", true,
384                                   "#version 300 es\n"
385                                   "in highp vec4 a_position;\n"
386                                   "in highp vec4 a_coords;\n"
387                                   "out highp vec4 v_color;\n\n"
388                                   "vec4 getColor (void)\n"
389                                   "{\n"
390                                   "    return vec4(a_coords.xyz, 1.0);\n"
391                                   "    return vec4(a_coords.wzy, 1.0);\n"
392                                   "}\n\n"
393                                   "void main (void)\n"
394                                   "{\n"
395                                   "    gl_Position = a_position;\n"
396                                   "    v_color = getColor();\n"
397                                   "}\n",
398                                   evalReturnAlways));
399     addChild(new ShaderReturnCase(m_context, "double_return_fragment", "Unconditional double return in function", false,
400                                   "#version 300 es\n"
401                                   "in mediump vec4 v_coords;\n"
402                                   "layout(location = 0) out mediump vec4 o_color;\n\n"
403                                   "mediump vec4 getColor (void)\n"
404                                   "{\n"
405                                   "    return vec4(v_coords.xyz, 1.0);\n"
406                                   "    return vec4(v_coords.wzy, 1.0);\n"
407                                   "}\n\n"
408                                   "void main (void)\n"
409                                   "{\n"
410                                   "    o_color = getColor();\n"
411                                   "}\n",
412                                   evalReturnAlways));
413 
414     // Last statement in main.
415     addChild(new ShaderReturnCase(m_context, "last_statement_in_main_vertex", "Return as a final statement in main()",
416                                   true,
417                                   "#version 300 es\n"
418                                   "in highp vec4 a_position;\n"
419                                   "in highp vec4 a_coords;\n"
420                                   "out highp vec4 v_color;\n\n"
421                                   "void main (void)\n"
422                                   "{\n"
423                                   "    gl_Position = a_position;\n"
424                                   "    v_color = vec4(a_coords.xyz, 1.0);\n"
425                                   "    return;\n"
426                                   "}\n",
427                                   evalReturnAlways));
428     addChild(new ShaderReturnCase(m_context, "last_statement_in_main_fragment", "Return as a final statement in main()",
429                                   false,
430                                   "#version 300 es\n"
431                                   "in mediump vec4 v_coords;\n"
432                                   "layout(location = 0) out mediump vec4 o_color;\n\n"
433                                   "void main (void)\n"
434                                   "{\n"
435                                   "    o_color = vec4(v_coords.xyz, 1.0);\n"
436                                   "    return;\n"
437                                   "}\n",
438                                   evalReturnAlways));
439 
440     // Return between output variable writes.
441     for (int inFunc = 0; inFunc < 2; inFunc++)
442     {
443         for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
444         {
445             for (int isFragment = 0; isFragment < 2; isFragment++)
446             {
447                 string name = string("output_write_") + (inFunc ? "in_func_" : "") +
448                               getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
449                 string desc = string(getReturnModeDesc((ReturnMode)returnMode)) +
450                               (inFunc ? " in user-defined function" : " in main()") + " between output writes";
451 
452                 addChild(makeOutputWriteReturnCase(m_context, name.c_str(), desc.c_str(), inFunc != 0,
453                                                    (ReturnMode)returnMode, isFragment == 0));
454             }
455         }
456     }
457 
458     // Conditional return statement in loop.
459     for (int isDynamicLoop = 0; isDynamicLoop < 2; isDynamicLoop++)
460     {
461         for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
462         {
463             for (int isFragment = 0; isFragment < 2; isFragment++)
464             {
465                 string name = string("return_in_") + (isDynamicLoop ? "dynamic" : "static") + "_loop_" +
466                               getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
467                 string description = string(getReturnModeDesc((ReturnMode)returnMode)) + " in loop";
468                 addChild(makeReturnInLoopCase(m_context, name.c_str(), description.c_str(), isDynamicLoop != 0,
469                                               (ReturnMode)returnMode, isFragment == 0));
470             }
471         }
472     }
473 
474     // Unconditional return in infinite loop.
475     addChild(new ShaderReturnCase(m_context, "return_in_infinite_loop_vertex", "Return in infinite loop", true,
476                                   "#version 300 es\n"
477                                   "in highp vec4 a_position;\n"
478                                   "in highp vec4 a_coords;\n"
479                                   "out highp vec4 v_color;\n"
480                                   "uniform int ui_zero;\n\n"
481                                   "highp vec4 getCoords (void)\n"
482                                   "{\n"
483                                   "    for (int i = 1; i < 10; i += ui_zero)\n"
484                                   "        return a_coords;\n"
485                                   "    return a_coords.wzyx;\n"
486                                   "}\n\n"
487                                   "void main (void)\n"
488                                   "{\n"
489                                   "    gl_Position = a_position;\n"
490                                   "    v_color = vec4(getCoords().xyz, 1.0);\n"
491                                   "    return;\n"
492                                   "}\n",
493                                   evalReturnAlways));
494     addChild(new ShaderReturnCase(m_context, "return_in_infinite_loop_fragment", "Return in infinite loop", false,
495                                   "#version 300 es\n"
496                                   "in mediump vec4 v_coords;\n"
497                                   "layout(location = 0) out mediump vec4 o_color;\n"
498                                   "uniform int ui_zero;\n\n"
499                                   "mediump vec4 getCoords (void)\n"
500                                   "{\n"
501                                   "    for (int i = 1; i < 10; i += ui_zero)\n"
502                                   "        return v_coords;\n"
503                                   "    return v_coords.wzyx;\n"
504                                   "}\n\n"
505                                   "void main (void)\n"
506                                   "{\n"
507                                   "    o_color = vec4(getCoords().xyz, 1.0);\n"
508                                   "    return;\n"
509                                   "}\n",
510                                   evalReturnAlways));
511 }
512 
513 } // namespace Functional
514 } // namespace gles3
515 } // namespace deqp
516