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