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