1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2015-2016 The Khronos Group Inc. 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 22 */ /*-------------------------------------------------------------------*/ 23 24/*! 25 * \file glcShaderNegativeTests.cpp 26 * \brief Negative tests for shaders and interface matching. 27 */ /*-------------------------------------------------------------------*/ 28 29#include "glcShaderNegativeTests.hpp" 30#include "deString.h" 31#include "deStringUtil.hpp" 32#include "gluContextInfo.hpp" 33#include "gluShaderProgram.hpp" 34#include "glw.h" 35#include "tcuStringTemplate.hpp" 36#include "tcuTestLog.hpp" 37 38namespace deqp 39{ 40 41using tcu::TestLog; 42using namespace glu; 43 44struct ShaderVariants 45{ 46 GLSLVersion minimum_supported_version; 47 const char* vertex_precision; 48 const char* vertex_body; 49 const char* frag_precision; 50 const char* frag_body; 51 bool should_link; 52}; 53 54class ShaderUniformInitializeGlobalCase : public TestCase 55{ 56public: 57 ShaderUniformInitializeGlobalCase(Context& context, const char* name, const char* description, 58 GLSLVersion glslVersion) 59 : TestCase(context, name, description), m_glslVersion(glslVersion) 60 { 61 } 62 63 ~ShaderUniformInitializeGlobalCase() 64 { 65 // empty 66 } 67 68 IterateResult iterate() 69 { 70 qpTestResult result = QP_TEST_RESULT_PASS; 71 72 static const char vertex_source_template[] = 73 "${VERSION_DECL}\n" 74 "precision mediump float;\n" 75 "uniform vec4 nonconstantexpression;\n" 76 "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n" 77 "vec4 globalconstant1 = nonconstantexpression;\n" 78 "\n" 79 "void main(void) { gl_Position = globalconstant0+globalconstant1; }\n"; 80 static const char fragment_source_template[] = "${VERSION_DECL}\n" 81 "precision mediump float;\n" 82 "uniform vec4 nonconstantexpression;\n" 83 "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n" 84 "vec4 globalconstant1 = nonconstantexpression;\n" 85 "\n" 86 "void main(void) { }\n"; 87 88 std::map<std::string, std::string> args; 89 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion); 90 91 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args); 92 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args); 93 94 // Setup program. 95 ShaderProgram program(m_context.getRenderContext(), 96 makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str())); 97 98 // GLSL ES does not allow initialization of global variables with non-constant 99 // expressions, but GLSL does. 100 // Check that either compilation or linking fails for ES, and that everything 101 // succeeds for GL. 102 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk; 103 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk; 104 bool linkOk = program.getProgramInfo().linkOk; 105 106 if (glslVersionIsES(m_glslVersion)) 107 { 108 if (vertexOk && fragmentOk && linkOk) 109 result = QP_TEST_RESULT_FAIL; 110 } 111 else 112 { 113 if (!vertexOk && !fragmentOk && !linkOk) 114 result = QP_TEST_RESULT_FAIL; 115 } 116 117 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 118 119 return STOP; 120 } 121 122protected: 123 GLSLVersion m_glslVersion; 124}; 125 126class ShaderUniformPrecisionLinkCase : public TestCase 127{ 128public: 129 ShaderUniformPrecisionLinkCase(Context& context, const char* name, const char* description, 130 const ShaderVariants* shaderVariants, unsigned int shaderVariantsCount, 131 GLSLVersion glslVersion) 132 : TestCase(context, name, description) 133 , m_glslVersion(glslVersion) 134 , m_shaderVariants(shaderVariants) 135 , m_shaderVariantsCount(shaderVariantsCount) 136 { 137 } 138 139 ~ShaderUniformPrecisionLinkCase() 140 { 141 // empty 142 } 143 144 IterateResult iterate() 145 { 146 TestLog& log = m_testCtx.getLog(); 147 qpTestResult result = QP_TEST_RESULT_PASS; 148 149 static const char vertex_source_template[] = "${VERSION_DECL}\n" 150 "uniform ${PREC_QUALIFIER} vec4 value;\n" 151 "\n" 152 "void main(void) { ${BODY} }\n"; 153 154 static const char fragment_source_template[] = "${VERSION_DECL}\n" 155 "out highp vec4 result;\n" 156 "uniform ${PREC_QUALIFIER} vec4 value;\n" 157 "\n" 158 "void main(void) { ${BODY} }\n"; 159 160 for (unsigned int i = 0; i < m_shaderVariantsCount; i++) 161 { 162 std::map<std::string, std::string> args; 163 164 if (m_glslVersion <= m_shaderVariants[i].minimum_supported_version) 165 { 166 continue; 167 } 168 169 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion); 170 args["PREC_QUALIFIER"] = m_shaderVariants[i].vertex_precision; 171 args["BODY"] = m_shaderVariants[i].vertex_body; 172 std::string vcode = tcu::StringTemplate(vertex_source_template).specialize(args); 173 174 args["PREC_QUALIFIER"] = m_shaderVariants[i].frag_precision; 175 args["BODY"] = m_shaderVariants[i].frag_body; 176 std::string fcode = tcu::StringTemplate(fragment_source_template).specialize(args); 177 178 // Setup program. 179 ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vcode.c_str(), fcode.c_str())); 180 181 // Check that compile/link results are what we expect. 182 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk; 183 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk; 184 bool linkOk = program.getProgramInfo().linkOk; 185 const char* failReason = DE_NULL; 186 187 if (!vertexOk || !fragmentOk) 188 { 189 failReason = "expected shaders to compile, but failed."; 190 } 191 else if (m_shaderVariants[i].should_link && !linkOk) 192 { 193 failReason = "expected shaders to link, but failed."; 194 } 195 else if (!m_shaderVariants[i].should_link && linkOk) 196 { 197 failReason = "expected shaders to fail linking, but succeeded."; 198 } 199 200 if (failReason != DE_NULL) 201 { 202 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage; 203 result = QP_TEST_RESULT_FAIL; 204 } 205 } 206 207 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 208 209 return STOP; 210 } 211 212protected: 213 GLSLVersion m_glslVersion; 214 const ShaderVariants* m_shaderVariants; 215 unsigned int m_shaderVariantsCount; 216}; 217 218class ShaderConstantSequenceExpressionCase : public TestCase 219{ 220public: 221 ShaderConstantSequenceExpressionCase(Context& context, const char* name, const char* description, 222 GLSLVersion glslVersion) 223 : TestCase(context, name, description), m_glslVersion(glslVersion) 224 { 225 } 226 227 ~ShaderConstantSequenceExpressionCase() 228 { 229 // empty 230 } 231 232 IterateResult iterate() 233 { 234 qpTestResult result = QP_TEST_RESULT_PASS; 235 236 static const char vertex_source_template[] = "${VERSION_DECL}\n" 237 "precision mediump float;\n" 238 "const int test = (1, 2);\n" 239 "\n" 240 "void main(void) { gl_Position = vec4(test); }\n"; 241 242 static const char fragment_source_template[] = "${VERSION_DECL}\n" 243 "precision mediump float;\n" 244 "\n" 245 "void main(void) { }\n"; 246 247 std::map<std::string, std::string> args; 248 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion); 249 250 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args); 251 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args); 252 253 // Setup program. 254 ShaderProgram program(m_context.getRenderContext(), 255 makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str())); 256 257 // GLSL does not allow the sequence operator in a constant expression 258 // Check that either compilation or linking fails 259 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk; 260 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk; 261 bool linkOk = program.getProgramInfo().linkOk; 262 263 bool run_test_es = (glslVersionIsES(m_glslVersion) && m_glslVersion > GLSL_VERSION_100_ES); 264 bool run_test_desktop = (m_glslVersion > GLSL_VERSION_420); 265 if (run_test_es || run_test_desktop) 266 { 267 if (vertexOk && fragmentOk && linkOk) 268 result = QP_TEST_RESULT_FAIL; 269 } 270 271 m_testCtx.setTestResult(result, qpGetTestResultName(result)); 272 273 return STOP; 274 } 275 276protected: 277 GLSLVersion m_glslVersion; 278}; 279 280class ShaderNonPrecisionQualifiersStructCase : public TestCase 281{ 282public: 283 ShaderNonPrecisionQualifiersStructCase(Context& context, const char* name, const char* description, 284 GLSLVersion glslVersion) 285 : TestCase(context, name, description), m_glslVersion(glslVersion) 286 { 287 } 288 289 ~ShaderNonPrecisionQualifiersStructCase() 290 { 291 // empty 292 } 293 294 IterateResult iterate() 295 { 296 static const char* qualifier_values[] = 297 { 298 // Storage Qualifiers 299 "const", 300 "in", 301 "out", 302 "attribute", 303 "uniform", 304 "varying", 305 "buffer", 306 "shared", 307 308 // Interpolation Qualifiers 309 "smooth in", 310 "flat in", 311 "noperspective in", 312 "smooth out", 313 "flat out", 314 "noperspective out", 315 316 // Invariant Qualifier 317 "invariant", 318 319 // Precise Qualifier 320 "precise", 321 322 // Memory Qualifiers 323 "coherent", 324 "volatile", 325 "restrict", 326 "readonly", 327 "writeonly", 328 }; 329 static const unsigned qualifier_count = sizeof(qualifier_values) / sizeof(qualifier_values[0]); 330 331 static const char* layout_values[] = 332 { 333 "(shared)", 334 "(packed)", 335 "(std140)", 336 "(std430)", 337 338 "(row_major)", 339 "(column_major)", 340 }; 341 static const unsigned layout_count = sizeof(layout_values) / sizeof(layout_values[0]); 342 343 const std::string layout_str = "layout"; 344 345 std::map<std::string, std::string> args; 346 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion); 347 348 // Vertex and fragment shaders 349 { 350 // Layout qualifier test 351 args["QUALIFIER"] = layout_str; 352 for (unsigned i = 0; i < layout_count; ++i) 353 { 354 args["LAYOUT_VALUE"] = layout_values[i]; 355 if (testVertexFragment(args, layout_str + layout_values[i])) 356 return STOP; 357 } 358 359 // Remaining qualifier tests 360 args["LAYOUT_VALUE"] = ""; 361 for (unsigned i = 0; i < qualifier_count; ++i) 362 { 363 args["QUALIFIER"] = qualifier_values[i]; 364 if (testVertexFragment(args, qualifier_values[i])) 365 return STOP; 366 } 367 } 368 369 // Compute shader, not available for GLES2 and GLES3 370 if (!glslVersionIsES(m_glslVersion) || m_glslVersion >= GLSL_VERSION_310_ES) 371 { 372 // Layout qualifier test 373 args["QUALIFIER"] = layout_str; 374 for (unsigned i = 0; i < layout_count; ++i) 375 { 376 args["LAYOUT_VALUE"] = layout_values[i]; 377 if (testCompute(args, layout_str + layout_values[i])) 378 return STOP; 379 } 380 381 // Remaining qualifier tests 382 args["LAYOUT_VALUE"] = ""; 383 for (unsigned i = 0; i < qualifier_count; ++i) 384 { 385 args["QUALIFIER"] = qualifier_values[i]; 386 if (testCompute(args, qualifier_values[i])) 387 return STOP; 388 } 389 } 390 391 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS)); 392 393 return STOP; 394 } 395 396protected: 397 bool testVertexFragment(const std::map<std::string, std::string>& args, const std::string& qualifier_name) 398 { 399 static const char* vertex_source_template = "${VERSION_DECL}\n" 400 "precision mediump float;\n" 401 "struct Base\n" 402 "{\n" 403 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n" 404 "};\n" 405 "\n" 406 "void main(void)\n" 407 "{\n" 408 " gl_Position = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n" 409 "}\n"; 410 411 static const char* fragment_source_template = "${VERSION_DECL}\n" 412 "precision mediump float;\n" 413 "struct Base\n" 414 "{\n" 415 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n" 416 "};\n" 417 "\n" 418 "void main(void) { }\n"; 419 420 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args); 421 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args); 422 ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str())); 423 if (program.getShaderInfo(SHADERTYPE_VERTEX).compileOk || program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk) 424 { 425 m_testCtx.getLog() << TestLog::Message << "ERROR: expected shaders not to compile, but failed with \'" 426 << qualifier_name << "\' qualifier." << TestLog::EndMessage; 427 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL)); 428 return true; 429 } 430 return false; 431 } 432 433 bool testCompute(const std::map<std::string, std::string>& args, const std::string& qualifier_name) 434 { 435 static const char* compute_source_template = "${VERSION_DECL}\n" 436 "precision mediump float;\n" 437 "struct Base\n" 438 "{\n" 439 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n" 440 "};\n" 441 "\n" 442 "void main(void) { }\n"; 443 444 std::string compute_code = tcu::StringTemplate(compute_source_template).specialize(args); 445 ProgramSources sources; 446 sources.sources[SHADERTYPE_COMPUTE].emplace_back(compute_code); 447 ShaderProgram program(m_context.getRenderContext(), sources); 448 if (program.getShaderInfo(SHADERTYPE_COMPUTE).compileOk) 449 { 450 m_testCtx.getLog() << TestLog::Message << "ERROR: expected compute shader not to compile, but failed with \'" 451 << qualifier_name << "\' qualifier." << TestLog::EndMessage; 452 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL)); 453 return true; 454 } 455 return false; 456 } 457 458 GLSLVersion m_glslVersion; 459}; 460 461ShaderNegativeTests::ShaderNegativeTests(Context& context, GLSLVersion glslVersion) 462 : TestCaseGroup(context, "negative", "Shader Negative tests"), m_glslVersion(glslVersion) 463{ 464 // empty 465} 466 467ShaderNegativeTests::~ShaderNegativeTests() 468{ 469 // empty 470} 471 472void ShaderNegativeTests::init(void) 473{ 474 addChild(new ShaderUniformInitializeGlobalCase( 475 m_context, "initialize", "Verify initialization of globals with non-constant expressions fails on ES.", 476 m_glslVersion)); 477 478 addChild(new ShaderConstantSequenceExpressionCase( 479 m_context, "constant_sequence", "Verify that the sequence operator cannot be used as a constant expression.", 480 m_glslVersion)); 481 482 addChild(new ShaderNonPrecisionQualifiersStructCase( 483 m_context, "non_precision_qualifiers_in_struct_members", "Verify non-precision qualifiers in struct members are not allowed.", 484 m_glslVersion)); 485 486 if (isGLSLVersionSupported(m_context.getRenderContext().getType(), GLSL_VERSION_320_ES)) 487 { 488 static const ShaderVariants used_variables_variants[] = { 489 /* These variants should pass since the precision qualifiers match. 490 * These variants require highp to be supported, so will not be run for GLSL_VERSION_100_ES. 491 */ 492 { GLSL_VERSION_300_ES, "", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true }, 493 { GLSL_VERSION_300_ES, "highp", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true }, 494 495 /* Use highp in vertex shaders, mediump in fragment shaders. Check variations as above. 496 * These variants should fail since the precision qualifiers do not match, and matching is done 497 * based on declaration - independent of static use. 498 */ 499 { GLSL_VERSION_100_ES, "", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false }, 500 { GLSL_VERSION_100_ES, "highp", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false }, 501 }; 502 unsigned int used_variables_variants_count = sizeof(used_variables_variants) / sizeof(ShaderVariants); 503 504 addChild(new ShaderUniformPrecisionLinkCase( 505 m_context, "used_uniform_precision_matching", 506 "Verify that linking fails if precision qualifiers on default uniform do not match", 507 used_variables_variants, used_variables_variants_count, m_glslVersion)); 508 } 509} 510 511} // deqp 512