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 Invariance tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fShaderInvarianceTests.hpp" 25 #include "deStringUtil.hpp" 26 #include "deRandom.hpp" 27 #include "gluContextInfo.hpp" 28 #include "gluRenderContext.hpp" 29 #include "gluShaderProgram.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "glwFunctions.hpp" 32 #include "glwEnums.hpp" 33 #include "tcuRenderTarget.hpp" 34 #include "tcuTestLog.hpp" 35 #include "tcuSurface.hpp" 36 #include "tcuTextureUtil.hpp" 37 #include "tcuStringTemplate.hpp" 38 39 40 namespace deqp 41 { 42 namespace gles3 43 { 44 namespace Functional 45 { 46 namespace 47 { 48 49 class FormatArgumentList; 50 51 static tcu::Vec4 genRandomVector (de::Random& rnd) 52 { 53 tcu::Vec4 retVal; 54 55 retVal.x() = rnd.getFloat(-1.0f, 1.0f); 56 retVal.y() = rnd.getFloat(-1.0f, 1.0f); 57 retVal.z() = rnd.getFloat(-1.0f, 1.0f); 58 retVal.w() = rnd.getFloat( 0.2f, 1.0f); 59 60 return retVal; 61 } 62 63 class FormatArgument 64 { 65 public: 66 FormatArgument (const char* name, const std::string& value); 67 68 private: 69 friend class FormatArgumentList; 70 71 const char* const m_name; 72 const std::string m_value; 73 }; 74 75 FormatArgument::FormatArgument (const char* name, const std::string& value) 76 : m_name (name) 77 , m_value (value) 78 { 79 } 80 81 class FormatArgumentList 82 { 83 public: 84 FormatArgumentList (void); 85 86 FormatArgumentList& operator<< (const FormatArgument&); 87 const std::map<std::string, std::string>& getArguments (void) const; 88 89 private: 90 std::map<std::string, std::string> m_formatArguments; 91 }; 92 93 FormatArgumentList::FormatArgumentList (void) 94 { 95 } 96 97 FormatArgumentList& FormatArgumentList::operator<< (const FormatArgument& arg) 98 { 99 m_formatArguments[arg.m_name] = arg.m_value; 100 return *this; 101 } 102 103 const std::map<std::string, std::string>& FormatArgumentList::getArguments (void) const 104 { 105 return m_formatArguments; 106 } 107 108 static std::string formatGLSL (const char* templateString, const FormatArgumentList& args) 109 { 110 const std::map<std::string, std::string>& params = args.getArguments(); 111 112 return tcu::StringTemplate(std::string(templateString)).specialize(params); 113 } 114 115 /*--------------------------------------------------------------------*//*! 116 * \brief Vertex shader invariance test 117 * 118 * Test vertex shader invariance by drawing a test pattern two times, each 119 * time with a different shader. Shaders have set identical values to 120 * invariant gl_Position using identical expressions. No fragments from the 121 * first pass using should remain visible. 122 *//*--------------------------------------------------------------------*/ 123 class InvarianceTest : public TestCase 124 { 125 public: 126 struct ShaderPair 127 { 128 std::string vertexShaderSource0; 129 std::string fragmentShaderSource0; 130 std::string vertexShaderSource1; 131 std::string fragmentShaderSource1; 132 }; 133 134 InvarianceTest (Context& ctx, const char* name, const char* desc); 135 ~InvarianceTest (void); 136 137 void init (void); 138 void deinit (void); 139 IterateResult iterate (void); 140 141 private: 142 virtual ShaderPair genShaders (void) const = DE_NULL; 143 bool checkImage (const tcu::Surface&) const; 144 145 glu::ShaderProgram* m_shader0; 146 glu::ShaderProgram* m_shader1; 147 glw::GLuint m_arrayBuf; 148 int m_verticesInPattern; 149 150 const int m_renderSize; 151 }; 152 153 InvarianceTest::InvarianceTest (Context& ctx, const char* name, const char* desc) 154 : TestCase (ctx, name, desc) 155 , m_shader0 (DE_NULL) 156 , m_shader1 (DE_NULL) 157 , m_arrayBuf (0) 158 , m_verticesInPattern (0) 159 , m_renderSize (256) 160 { 161 } 162 163 InvarianceTest::~InvarianceTest (void) 164 { 165 deinit(); 166 } 167 168 void InvarianceTest::init (void) 169 { 170 // Invariance tests require drawing to the screen and reading back results. 171 // Tests results are not reliable if the resolution is too small 172 { 173 if (m_context.getRenderTarget().getWidth() < m_renderSize || 174 m_context.getRenderTarget().getHeight() < m_renderSize) 175 throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_renderSize) + "x" + de::toString(m_renderSize)); 176 } 177 178 // Gen shaders 179 { 180 ShaderPair vertexShaders = genShaders(); 181 182 m_shader0 = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource0) << glu::FragmentSource(vertexShaders.fragmentShaderSource0)); 183 if (!m_shader0->isOk()) 184 { 185 m_testCtx.getLog() << *m_shader0; 186 throw tcu::TestError("Test shader compile failed."); 187 } 188 189 m_shader1 = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource1) << glu::FragmentSource(vertexShaders.fragmentShaderSource1)); 190 if (!m_shader1->isOk()) 191 { 192 m_testCtx.getLog() << *m_shader1; 193 throw tcu::TestError("Test shader compile failed."); 194 } 195 196 // log 197 m_testCtx.getLog() 198 << tcu::TestLog::Message << "Shader 1:" << tcu::TestLog::EndMessage 199 << *m_shader0 200 << tcu::TestLog::Message << "Shader 2:" << tcu::TestLog::EndMessage 201 << *m_shader1; 202 } 203 204 // Gen test pattern 205 { 206 const int numTriangles = 72; 207 de::Random rnd (123); 208 std::vector<tcu::Vec4> triangles (numTriangles * 3 * 2); 209 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 210 211 // Narrow triangle pattern 212 for (int triNdx = 0; triNdx < numTriangles; ++triNdx) 213 { 214 const tcu::Vec4 vertex1 = genRandomVector(rnd); 215 const tcu::Vec4 vertex2 = genRandomVector(rnd); 216 const tcu::Vec4 vertex3 = vertex2 + genRandomVector(rnd) * 0.01f; // generate narrow triangles 217 218 triangles[triNdx*3 + 0] = vertex1; 219 triangles[triNdx*3 + 1] = vertex2; 220 triangles[triNdx*3 + 2] = vertex3; 221 } 222 223 // Normal triangle pattern 224 for (int triNdx = 0; triNdx < numTriangles; ++triNdx) 225 { 226 triangles[(numTriangles + triNdx)*3 + 0] = genRandomVector(rnd); 227 triangles[(numTriangles + triNdx)*3 + 1] = genRandomVector(rnd); 228 triangles[(numTriangles + triNdx)*3 + 2] = genRandomVector(rnd); 229 } 230 231 // upload 232 gl.genBuffers(1, &m_arrayBuf); 233 gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf); 234 gl.bufferData(GL_ARRAY_BUFFER, (int)(triangles.size() * sizeof(tcu::Vec4)), &triangles[0], GL_STATIC_DRAW); 235 GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen"); 236 237 m_verticesInPattern = numTriangles * 3; 238 } 239 } 240 241 void InvarianceTest::deinit (void) 242 { 243 delete m_shader0; 244 delete m_shader1; 245 246 m_shader0 = DE_NULL; 247 m_shader1 = DE_NULL; 248 249 if (m_arrayBuf) 250 { 251 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf); 252 m_arrayBuf = 0; 253 } 254 } 255 256 InvarianceTest::IterateResult InvarianceTest::iterate (void) 257 { 258 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 259 const bool depthBufferExists = m_context.getRenderTarget().getDepthBits() != 0; 260 tcu::Surface resultSurface (m_renderSize, m_renderSize); 261 bool error = false; 262 263 // Prepare draw 264 gl.clearColor (0.0f, 0.0f, 0.0f, 1.0f); 265 gl.clear (GL_COLOR_BUFFER_BIT); 266 gl.viewport (0, 0, m_renderSize, m_renderSize); 267 gl.bindBuffer (GL_ARRAY_BUFFER, m_arrayBuf); 268 GLU_EXPECT_NO_ERROR (gl.getError(), "setup draw"); 269 270 m_testCtx.getLog() << tcu::TestLog::Message << "Testing position invariance." << tcu::TestLog::EndMessage; 271 272 // Draw position check passes 273 for (int passNdx = 0; passNdx < 2; ++passNdx) 274 { 275 const glu::ShaderProgram& shader = (passNdx == 0) ? (*m_shader0) : (*m_shader1); 276 const glw::GLint positionLoc = gl.getAttribLocation(shader.getProgram(), "a_input"); 277 const glw::GLint colorLoc = gl.getUniformLocation(shader.getProgram(), "u_color"); 278 const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f); 279 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); 280 const tcu::Vec4 color = (passNdx == 0) ? (red) : (green); 281 const char* const colorStr = (passNdx == 0) ? ("red - purple") : ("green"); 282 283 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing position test pattern using shader " << (passNdx+1) << ". Primitive color: " << colorStr << "." << tcu::TestLog::EndMessage; 284 285 gl.useProgram (shader.getProgram()); 286 gl.uniform4fv (colorLoc, 1, color.getPtr()); 287 gl.enableVertexAttribArray (positionLoc); 288 gl.vertexAttribPointer (positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL); 289 gl.drawArrays (GL_TRIANGLES, 0, m_verticesInPattern); 290 gl.disableVertexAttribArray (positionLoc); 291 GLU_EXPECT_NO_ERROR (gl.getError(), "draw pass"); 292 } 293 294 // Read result 295 glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess()); 296 297 // Check there are no red pixels 298 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output. Expecting only green or background colored pixels." << tcu::TestLog::EndMessage; 299 error |= !checkImage(resultSurface); 300 301 if (!depthBufferExists) 302 { 303 m_testCtx.getLog() << tcu::TestLog::Message << "Depth buffer not available, skipping z-test." << tcu::TestLog::EndMessage; 304 } 305 else 306 { 307 // Test with Z-test 308 gl.clearDepthf (1.0f); 309 gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 310 gl.enable (GL_DEPTH_TEST); 311 312 m_testCtx.getLog() << tcu::TestLog::Message << "Testing position invariance with z-test. Enabling GL_DEPTH_TEST." << tcu::TestLog::EndMessage; 313 314 // Draw position check passes 315 for (int passNdx = 0; passNdx < 2; ++passNdx) 316 { 317 const glu::ShaderProgram& shader = (passNdx == 0) ? (*m_shader0) : (*m_shader1); 318 const glw::GLint positionLoc = gl.getAttribLocation(shader.getProgram(), "a_input"); 319 const glw::GLint colorLoc = gl.getUniformLocation(shader.getProgram(), "u_color"); 320 const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f); 321 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); 322 const tcu::Vec4 color = (passNdx == 0) ? (red) : (green); 323 const glw::GLenum depthFunc = (passNdx == 0) ? (GL_ALWAYS) : (GL_EQUAL); 324 const char* const depthFuncStr = (passNdx == 0) ? ("GL_ALWAYS") : ("GL_EQUAL"); 325 const char* const colorStr = (passNdx == 0) ? ("red - purple") : ("green"); 326 327 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing Z-test pattern using shader " << (passNdx+1) << ". Primitive color: " << colorStr << ". DepthFunc: " << depthFuncStr << tcu::TestLog::EndMessage; 328 329 gl.useProgram (shader.getProgram()); 330 gl.uniform4fv (colorLoc, 1, color.getPtr()); 331 gl.depthFunc (depthFunc); 332 gl.enableVertexAttribArray (positionLoc); 333 gl.vertexAttribPointer (positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL); 334 gl.drawArrays (GL_TRIANGLES, m_verticesInPattern, m_verticesInPattern); // !< buffer contains 2 m_verticesInPattern-sized patterns 335 gl.disableVertexAttribArray (positionLoc); 336 GLU_EXPECT_NO_ERROR (gl.getError(), "draw pass"); 337 } 338 339 // Read result 340 glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess()); 341 342 // Check there are no red pixels 343 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output. Expecting only green or background colored pixels." << tcu::TestLog::EndMessage; 344 error |= !checkImage(resultSurface); 345 } 346 347 // Report result 348 if (error) 349 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected variance between two invariant values"); 350 else 351 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 352 353 return STOP; 354 } 355 356 bool InvarianceTest::checkImage (const tcu::Surface& surface) const 357 { 358 const tcu::IVec4 okColor = tcu::IVec4(0, 255, 0, 255); 359 const tcu::RGBA errColor = tcu::RGBA(255, 0, 0, 255); 360 bool error = false; 361 tcu::Surface errorMask (m_renderSize, m_renderSize); 362 363 tcu::clear(errorMask.getAccess(), okColor); 364 365 for (int y = 0; y < m_renderSize; ++y) 366 for (int x = 0; x < m_renderSize; ++x) 367 { 368 const tcu::RGBA col = surface.getPixel(x, y); 369 370 if (col.getRed() != 0) 371 { 372 errorMask.setPixel(x, y, errColor); 373 error = true; 374 } 375 } 376 377 // report error 378 if (error) 379 { 380 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found (fragments from first render pass found). Variance detected." << tcu::TestLog::EndMessage; 381 m_testCtx.getLog() 382 << tcu::TestLog::ImageSet("Results", "Result verification") 383 << tcu::TestLog::Image("Result", "Result", surface) 384 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) 385 << tcu::TestLog::EndImageSet; 386 387 return false; 388 } 389 else 390 { 391 m_testCtx.getLog() << tcu::TestLog::Message << "No variance found." << tcu::TestLog::EndMessage; 392 m_testCtx.getLog() 393 << tcu::TestLog::ImageSet("Results", "Result verification") 394 << tcu::TestLog::Image("Result", "Result", surface) 395 << tcu::TestLog::EndImageSet; 396 397 return true; 398 } 399 } 400 401 class BasicInvarianceTest : public InvarianceTest 402 { 403 public: 404 BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2); 405 BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader); 406 ShaderPair genShaders (void) const; 407 408 private: 409 const std::string m_vertexShader1; 410 const std::string m_vertexShader2; 411 const std::string m_fragmentShader; 412 static const char* const s_basicFragmentShader; 413 }; 414 415 const char* const BasicInvarianceTest::s_basicFragmentShader = "#version 300 es\n" 416 "layout(location = 0) out mediump vec4 fragColor;\n" 417 "uniform mediump vec4 u_color;\n" 418 "in mediump vec4 v_unrelated;\n" 419 "void main ()\n" 420 "{\n" 421 " mediump float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n" 422 " fragColor = vec4(u_color.r, u_color.g, blue, u_color.a);\n" 423 "}\n"; 424 425 BasicInvarianceTest::BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2) 426 : InvarianceTest (ctx, name, desc) 427 , m_vertexShader1 (vertexShader1) 428 , m_vertexShader2 (vertexShader2) 429 , m_fragmentShader (s_basicFragmentShader) 430 { 431 } 432 433 BasicInvarianceTest::BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader) 434 : InvarianceTest (ctx, name, desc) 435 , m_vertexShader1 (vertexShader1) 436 , m_vertexShader2 (vertexShader2) 437 , m_fragmentShader (fragmentShader) 438 { 439 } 440 441 BasicInvarianceTest::ShaderPair BasicInvarianceTest::genShaders (void) const 442 { 443 ShaderPair retVal; 444 445 retVal.vertexShaderSource0 = m_vertexShader1; 446 retVal.vertexShaderSource1 = m_vertexShader2; 447 retVal.fragmentShaderSource0 = m_fragmentShader; 448 retVal.fragmentShaderSource1 = m_fragmentShader; 449 450 return retVal; 451 } 452 453 } // anonymous 454 455 ShaderInvarianceTests::ShaderInvarianceTests (Context& context) 456 : TestCaseGroup(context, "invariance", "Invariance tests") 457 { 458 } 459 460 ShaderInvarianceTests::~ShaderInvarianceTests (void) 461 { 462 } 463 464 void ShaderInvarianceTests::init (void) 465 { 466 static const struct PrecisionCase 467 { 468 glu::Precision prec; 469 const char* name; 470 471 // set literals in the glsl to be in the representable range 472 const char* highValue; // !< highValue < maxValue 473 const char* invHighValue; 474 const char* mediumValue; // !< mediumValue^2 < maxValue 475 const char* lowValue; // !< lowValue^4 < maxValue 476 const char* invlowValue; 477 int loopIterations; 478 int loopPartialIterations; 479 int loopNormalizationExponent; 480 const char* loopNormalizationConstantLiteral; 481 const char* loopMultiplier; 482 const char* sumLoopNormalizationConstantLiteral; 483 } precisions[] = 484 { 485 { glu::PRECISION_HIGHP, "highp", "1.0e20", "1.0e-20", "1.0e14", "1.0e9", "1.0e-9", 14, 11, 2, "1.0e4", "1.9", "1.0e3" }, 486 { glu::PRECISION_MEDIUMP, "mediump", "1.0e4", "1.0e-4", "1.0e2", "1.0e1", "1.0e-1", 13, 11, 2, "1.0e4", "1.9", "1.0e3" }, 487 { glu::PRECISION_LOWP, "lowp", "0.9", "1.1", "1.1", "1.15", "0.87", 6, 2, 0, "2.0", "1.1", "1.0" }, 488 }; 489 490 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); ++precNdx) 491 { 492 const char* const precisionName = precisions[precNdx].name; 493 const glu::Precision precision = precisions[precNdx].prec; 494 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, precisionName, "Invariance tests using the given precision."); 495 496 const FormatArgumentList args = FormatArgumentList() 497 << FormatArgument("VERSION", "#version 300 es\n") 498 << FormatArgument("IN", "in") 499 << FormatArgument("OUT", "out") 500 << FormatArgument("IN_PREC", precisionName) 501 << FormatArgument("HIGH_VALUE", de::toString(precisions[precNdx].highValue)) 502 << FormatArgument("HIGH_VALUE_INV", de::toString(precisions[precNdx].invHighValue)) 503 << FormatArgument("MEDIUM_VALUE", de::toString(precisions[precNdx].mediumValue)) 504 << FormatArgument("LOW_VALUE", de::toString(precisions[precNdx].lowValue)) 505 << FormatArgument("LOW_VALUE_INV", de::toString(precisions[precNdx].invlowValue)) 506 << FormatArgument("LOOP_ITERS", de::toString(precisions[precNdx].loopIterations)) 507 << FormatArgument("LOOP_ITERS_PARTIAL", de::toString(precisions[precNdx].loopPartialIterations)) 508 << FormatArgument("LOOP_NORM_FRACT_EXP", de::toString(precisions[precNdx].loopNormalizationExponent)) 509 << FormatArgument("LOOP_NORM_LITERAL", precisions[precNdx].loopNormalizationConstantLiteral) 510 << FormatArgument("LOOP_MULTIPLIER", precisions[precNdx].loopMultiplier) 511 << FormatArgument("SUM_LOOP_NORM_LITERAL", precisions[precNdx].sumLoopNormalizationConstantLiteral); 512 513 addChild(group); 514 515 // subexpression cases 516 { 517 // First shader shares "${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy" with unrelated output variable. Reordering might result in accuracy loss 518 // due to the high exponent. In the second shader, the high exponent may be removed during compilation. 519 520 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_0", "Shader shares a subexpression with an unrelated variable.", 521 formatGLSL( "${VERSION}" 522 "${IN} ${IN_PREC} vec4 a_input;\n" 523 "${OUT} mediump vec4 v_unrelated;\n" 524 "invariant gl_Position;\n" 525 "void main ()\n" 526 "{\n" 527 " v_unrelated = a_input.xzxz + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * (1.08 * a_input.zyzy * a_input.xzxz) * ${HIGH_VALUE_INV} * (a_input.z * a_input.zzxz - a_input.z * a_input.zzxz) + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) / ${HIGH_VALUE};\n" 528 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n" 529 "}\n", args), 530 formatGLSL( "${VERSION}" 531 "${IN} ${IN_PREC} vec4 a_input;\n" 532 "${OUT} mediump vec4 v_unrelated;\n" 533 "invariant gl_Position;\n" 534 "void main ()\n" 535 "{\n" 536 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 537 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n" 538 "}\n", args))); 539 540 // In the first shader, the unrelated variable "d" has mathematically the same expression as "e", but the different 541 // order of calculation might cause different results. 542 543 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_1", "Shader shares a subexpression with an unrelated variable.", 544 formatGLSL( "${VERSION}" 545 "${IN} ${IN_PREC} vec4 a_input;\n" 546 "${OUT} mediump vec4 v_unrelated;\n" 547 "invariant gl_Position;\n" 548 "void main ()\n" 549 "{\n" 550 " ${IN_PREC} vec4 a = ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy - ${HIGH_VALUE} * a_input.zzxx;\n" 551 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n" 552 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n" 553 " ${IN_PREC} vec4 d = (${LOW_VALUE} * a_input.yzxx) * (${LOW_VALUE} * a_input.yzzw) * (1.1*${LOW_VALUE_INV} * a_input.yzxx) * (${LOW_VALUE_INV} * a_input.xzzy);\n" 554 " ${IN_PREC} vec4 e = ((${LOW_VALUE} * a_input.yzxx) * (1.1*${LOW_VALUE_INV} * a_input.yzxx)) * ((${LOW_VALUE_INV} * a_input.xzzy) * (${LOW_VALUE} * a_input.yzzw));\n" 555 " v_unrelated = a + b + c + d + e;\n" 556 " gl_Position = a_input + fract(c) + e;\n" 557 "}\n", args), 558 formatGLSL( "${VERSION}" 559 "${IN} ${IN_PREC} vec4 a_input;\n" 560 "${OUT} mediump vec4 v_unrelated;\n" 561 "invariant gl_Position;\n" 562 "void main ()\n" 563 "{\n" 564 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n" 565 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n" 566 " ${IN_PREC} vec4 e = ((${LOW_VALUE} * a_input.yzxx) * (1.1*${LOW_VALUE_INV} * a_input.yzxx)) * ((${LOW_VALUE_INV} * a_input.xzzy) * (${LOW_VALUE} * a_input.yzzw));\n" 567 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 568 " gl_Position = a_input + fract(c) + e;\n" 569 "}\n", args))); 570 571 // Intermediate values used by an unrelated output variable 572 573 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_2", "Shader shares a subexpression with an unrelated variable.", 574 formatGLSL( "${VERSION}" 575 "${IN} ${IN_PREC} vec4 a_input;\n" 576 "${OUT} mediump vec4 v_unrelated;\n" 577 "invariant gl_Position;\n" 578 "void main ()\n" 579 "{\n" 580 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n" 581 " ${IN_PREC} vec4 b = (${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy)) * (${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy)) / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n" 582 " ${IN_PREC} vec4 c = a * a;\n" 583 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n" 584 " v_unrelated = a + b + c + d;\n" 585 " gl_Position = a_input + d;\n" 586 "}\n", args), 587 formatGLSL( "${VERSION}" 588 "${IN} ${IN_PREC} vec4 a_input;\n" 589 "${OUT} mediump vec4 v_unrelated;\n" 590 "invariant gl_Position;\n" 591 "void main ()\n" 592 "{\n" 593 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n" 594 " ${IN_PREC} vec4 c = a * a;\n" 595 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n" 596 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 597 " gl_Position = a_input + d;\n" 598 "}\n", args))); 599 600 // Invariant value can be calculated using unrelated value 601 602 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_3", "Shader shares a subexpression with an unrelated variable.", 603 formatGLSL( "${VERSION}" 604 "${IN} ${IN_PREC} vec4 a_input;\n" 605 "${OUT} mediump vec4 v_unrelated;\n" 606 "invariant gl_Position;\n" 607 "void main ()\n" 608 "{\n" 609 " ${IN_PREC} float x = a_input.x * 0.2;\n" 610 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n" 611 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n" 612 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n" 613 " ${IN_PREC} vec4 f = x*a + x*b + x*c;\n" 614 " v_unrelated = f;\n" 615 " ${IN_PREC} vec4 g = x * (a + b + c);\n" 616 " gl_Position = a_input + g;\n" 617 "}\n", args), 618 formatGLSL( "${VERSION}" 619 "${IN} ${IN_PREC} vec4 a_input;\n" 620 "${OUT} mediump vec4 v_unrelated;\n" 621 "invariant gl_Position;\n" 622 "void main ()\n" 623 "{\n" 624 " ${IN_PREC} float x = a_input.x * 0.2;\n" 625 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n" 626 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n" 627 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n" 628 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 629 " ${IN_PREC} vec4 g = x * (a + b + c);\n" 630 " gl_Position = a_input + g;\n" 631 "}\n", args))); 632 } 633 634 // shared subexpression of different precision 635 { 636 for (int precisionOther = glu::PRECISION_LOWP; precisionOther != glu::PRECISION_LAST; ++precisionOther) 637 { 638 const char* const unrelatedPrec = glu::getPrecisionName((glu::Precision)precisionOther); 639 const glu::Precision minPrecision = (precisionOther < (int)precision) ? ((glu::Precision)precisionOther) : (precision); 640 const char* const multiplierStr = (minPrecision == glu::PRECISION_LOWP) ? ("0.8, 0.4, -0.2, 0.3") : ("1.0e1, 5.0e2, 2.0e2, 1.0"); 641 const char* const normalizationStrUsed = (minPrecision == glu::PRECISION_LOWP) ? ("vec4(fract(used2).xyz, 0.0)") : ("vec4(fract(used2 / 1.0e2).xyz - fract(used2 / 1.0e3).xyz, 0.0)"); 642 const char* const normalizationStrUnrelated = (minPrecision == glu::PRECISION_LOWP) ? ("vec4(fract(unrelated2).xyz, 0.0)") : ("vec4(fract(unrelated2 / 1.0e2).xyz - fract(unrelated2 / 1.0e3).xyz, 0.0)"); 643 644 group->addChild(new BasicInvarianceTest(m_context, ("subexpression_precision_" + std::string(unrelatedPrec)).c_str(), "Shader shares subexpression of different precision with an unrelated variable.", 645 formatGLSL( "${VERSION}" 646 "${IN} ${IN_PREC} vec4 a_input;\n" 647 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n" 648 "invariant gl_Position;\n" 649 "void main ()\n" 650 "{\n" 651 " ${UNRELATED_PREC} vec4 unrelated0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n" 652 " ${UNRELATED_PREC} vec4 unrelated1 = vec4(${MULTIPLIER}) * unrelated0.xywz + unrelated0;\n" 653 " ${UNRELATED_PREC} vec4 unrelated2 = refract(unrelated1, unrelated0, distance(unrelated0, unrelated1));\n" 654 " v_unrelated = a_input + 0.02 * ${NORMALIZE_UNRELATED};\n" 655 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n" 656 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n" 657 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n" 658 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n" 659 "}\n", FormatArgumentList(args) 660 << FormatArgument("UNRELATED_PREC", unrelatedPrec) 661 << FormatArgument("MULTIPLIER", multiplierStr) 662 << FormatArgument("NORMALIZE_USED", normalizationStrUsed) 663 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)), 664 formatGLSL( "${VERSION}" 665 "${IN} ${IN_PREC} vec4 a_input;\n" 666 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n" 667 "invariant gl_Position;\n" 668 "void main ()\n" 669 "{\n" 670 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 671 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n" 672 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n" 673 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n" 674 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n" 675 "}\n", FormatArgumentList(args) 676 << FormatArgument("UNRELATED_PREC", unrelatedPrec) 677 << FormatArgument("MULTIPLIER", multiplierStr) 678 << FormatArgument("NORMALIZE_USED", normalizationStrUsed) 679 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)))); 680 } 681 } 682 683 // loops 684 { 685 group->addChild(new BasicInvarianceTest(m_context, "loop_0", "Invariant value set using a loop", 686 formatGLSL( "${VERSION}" 687 "${IN} ${IN_PREC} vec4 a_input;\n" 688 "${OUT} highp vec4 v_unrelated;\n" 689 "invariant gl_Position;\n" 690 "void main ()\n" 691 "{\n" 692 " ${IN_PREC} vec4 value = a_input;\n" 693 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 694 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 695 " {\n" 696 " value *= ${LOOP_MULTIPLIER};\n" 697 " v_unrelated += value;\n" 698 " }\n" 699 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 700 "}\n", args), 701 formatGLSL( "${VERSION}" 702 "${IN} ${IN_PREC} vec4 a_input;\n" 703 "${OUT} highp vec4 v_unrelated;\n" 704 "invariant gl_Position;\n" 705 "void main ()\n" 706 "{\n" 707 " ${IN_PREC} vec4 value = a_input;\n" 708 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 709 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 710 " {\n" 711 " value *= ${LOOP_MULTIPLIER};\n" 712 " }\n" 713 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 714 "}\n", args))); 715 716 group->addChild(new BasicInvarianceTest(m_context, "loop_1", "Invariant value set using a loop", 717 formatGLSL( "${VERSION}" 718 "${IN} ${IN_PREC} vec4 a_input;\n" 719 "${OUT} mediump vec4 v_unrelated;\n" 720 "invariant gl_Position;\n" 721 "void main ()\n" 722 "{\n" 723 " ${IN_PREC} vec4 value = a_input;\n" 724 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 725 " {\n" 726 " value *= ${LOOP_MULTIPLIER};\n" 727 " if (i == ${LOOP_ITERS_PARTIAL})\n" 728 " v_unrelated = value;\n" 729 " }\n" 730 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 731 "}\n", args), 732 formatGLSL( "${VERSION}" 733 "${IN} ${IN_PREC} vec4 a_input;\n" 734 "${OUT} mediump vec4 v_unrelated;\n" 735 "invariant gl_Position;\n" 736 "void main ()\n" 737 "{\n" 738 " ${IN_PREC} vec4 value = a_input;\n" 739 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 740 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 741 " {\n" 742 " value *= ${LOOP_MULTIPLIER};\n" 743 " }\n" 744 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 745 "}\n", args))); 746 747 group->addChild(new BasicInvarianceTest(m_context, "loop_2", "Invariant value set using a loop", 748 formatGLSL( "${VERSION}" 749 "${IN} ${IN_PREC} vec4 a_input;\n" 750 "${OUT} mediump vec4 v_unrelated;\n" 751 "invariant gl_Position;\n" 752 "void main ()\n" 753 "{\n" 754 " ${IN_PREC} vec4 value = a_input;\n" 755 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n" 756 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 757 " {\n" 758 " value *= ${LOOP_MULTIPLIER};\n" 759 " if (i == ${LOOP_ITERS_PARTIAL})\n" 760 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n" 761 " else\n" 762 " v_unrelated = value + a_input;\n" 763 " }\n" 764 "}\n", args), 765 formatGLSL( "${VERSION}" 766 "${IN} ${IN_PREC} vec4 a_input;\n" 767 "${OUT} mediump vec4 v_unrelated;\n" 768 "invariant gl_Position;\n" 769 "void main ()\n" 770 "{\n" 771 " ${IN_PREC} vec4 value = a_input;\n" 772 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n" 773 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 774 " {\n" 775 " value *= ${LOOP_MULTIPLIER};\n" 776 " if (i == ${LOOP_ITERS_PARTIAL})\n" 777 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n" 778 " else\n" 779 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 780 " }\n" 781 "}\n", args))); 782 783 group->addChild(new BasicInvarianceTest(m_context, "loop_3", "Invariant value set using a loop", 784 formatGLSL( "${VERSION}" 785 "${IN} ${IN_PREC} vec4 a_input;\n" 786 "${OUT} mediump vec4 v_unrelated;\n" 787 "invariant gl_Position;\n" 788 "void main ()\n" 789 "{\n" 790 " ${IN_PREC} vec4 value = a_input;\n" 791 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n" 792 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 793 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 794 " {\n" 795 " value *= ${LOOP_MULTIPLIER};\n" 796 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 797 " v_unrelated = gl_Position.xyzx * a_input;\n" 798 " }\n" 799 "}\n", args), 800 formatGLSL( "${VERSION}" 801 "${IN} ${IN_PREC} vec4 a_input;\n" 802 "${OUT} mediump vec4 v_unrelated;\n" 803 "invariant gl_Position;\n" 804 "void main ()\n" 805 "{\n" 806 " ${IN_PREC} vec4 value = a_input;\n" 807 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n" 808 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 809 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 810 " {\n" 811 " value *= ${LOOP_MULTIPLIER};\n" 812 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n" 813 " }\n" 814 "}\n", args))); 815 816 group->addChild(new BasicInvarianceTest(m_context, "loop_4", "Invariant value set using a loop", 817 formatGLSL( "${VERSION}" 818 "${IN} ${IN_PREC} vec4 a_input;\n" 819 "${OUT} mediump vec4 v_unrelated;\n" 820 "invariant gl_Position;\n" 821 "void main ()\n" 822 "{\n" 823 " ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n" 824 " ${IN_PREC} vec4 value1 = a_input;\n" 825 " ${IN_PREC} vec4 value2 = a_input;\n" 826 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 827 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 828 " {\n" 829 " value1 *= ${LOOP_MULTIPLIER};\n" 830 " v_unrelated = v_unrelated*1.3 + a_input.xyzx * value1.xyxw;\n" 831 " }\n" 832 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 833 " {\n" 834 " value2 *= ${LOOP_MULTIPLIER};\n" 835 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n" 836 " }\n" 837 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n" 838 "}\n", args), 839 formatGLSL( "${VERSION}" 840 "${IN} ${IN_PREC} vec4 a_input;\n" 841 "${OUT} mediump vec4 v_unrelated;\n" 842 "invariant gl_Position;\n" 843 "void main ()\n" 844 "{\n" 845 " ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n" 846 " ${IN_PREC} vec4 value2 = a_input;\n" 847 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n" 848 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n" 849 " {\n" 850 " value2 *= ${LOOP_MULTIPLIER};\n" 851 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n" 852 " }\n" 853 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n" 854 "}\n", args))); 855 } 856 } 857 } 858 859 } // Functional 860 } // gles3 861 } // deqp 862