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