1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL (ES) 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 Compiler test case. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "glsShaderLibraryCase.hpp" 25 26 #include "tcuTestLog.hpp" 27 #include "tcuRenderTarget.hpp" 28 #include "tcuTextureUtil.hpp" 29 #include "tcuSurface.hpp" 30 31 #include "tcuStringTemplate.hpp" 32 #include "gluShaderProgram.hpp" 33 #include "gluPixelTransfer.hpp" 34 #include "gluDrawUtil.hpp" 35 #include "gluContextInfo.hpp" 36 #include "gluStrUtil.hpp" 37 38 #include "glwFunctions.hpp" 39 #include "glwEnums.hpp" 40 41 #include "deRandom.hpp" 42 #include "deInt32.h" 43 #include "deMath.h" 44 #include "deString.h" 45 #include "deStringUtil.hpp" 46 #include "deSharedPtr.hpp" 47 48 #include <map> 49 #include <vector> 50 #include <string> 51 #include <sstream> 52 53 namespace deqp 54 { 55 namespace gls 56 { 57 58 using namespace tcu; 59 using namespace glu; 60 using namespace glu::sl; 61 62 using std::vector; 63 using std::string; 64 using std::ostringstream; 65 using std::map; 66 using std::pair; 67 68 using de::SharedPtr; 69 70 // OpenGL-specific specialization utils 71 72 static vector<RequiredExtension> checkAndSpecializeExtensions (const vector<RequiredExtension>& src, 73 const ContextInfo& ctxInfo) 74 { 75 vector<RequiredExtension> specialized; 76 77 for (size_t extNdx = 0; extNdx < src.size(); ++extNdx) 78 { 79 const RequiredExtension& extension = src[extNdx]; 80 int supportedAltNdx = -1; 81 82 for (size_t alternativeNdx = 0; alternativeNdx < extension.alternatives.size(); ++alternativeNdx) 83 { 84 if (ctxInfo.isExtensionSupported(extension.alternatives[alternativeNdx].c_str())) 85 { 86 supportedAltNdx = (int)alternativeNdx; 87 break; 88 } 89 } 90 91 if (supportedAltNdx >= 0) 92 { 93 specialized.push_back(RequiredExtension(extension.alternatives[supportedAltNdx], extension.effectiveStages)); 94 } 95 else 96 { 97 // no extension(s). Make a nice output 98 std::ostringstream extensionList; 99 100 for (size_t ndx = 0; ndx < extension.alternatives.size(); ++ndx) 101 { 102 if (!extensionList.str().empty()) 103 extensionList << ", "; 104 extensionList << extension.alternatives[ndx]; 105 } 106 107 if (extension.alternatives.size() == 1) 108 throw tcu::NotSupportedError("Test requires extension " + extensionList.str()); 109 else 110 throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str()); 111 } 112 } 113 114 return specialized; 115 } 116 117 static void checkImplementationLimits (const vector<RequiredCapability>& requiredCaps, 118 const ContextInfo& ctxInfo) 119 { 120 for (size_t capNdx = 0; capNdx < requiredCaps.size(); ++capNdx) 121 { 122 const deUint32 pname = requiredCaps[capNdx].enumName; 123 const int requiredValue = requiredCaps[capNdx].referenceValue; 124 const int supportedValue = ctxInfo.getInt((int)pname); 125 126 if (supportedValue <= requiredValue) 127 throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " (" + de::toString(supportedValue) + ") >= " + de::toString(requiredValue)); 128 } 129 } 130 131 // Shader source specialization 132 133 // This functions builds a matching vertex shader for a 'both' case, when 134 // the fragment shader is being tested. 135 // We need to build attributes and varyings for each 'input'. 136 static string genVertexShader (const ShaderCaseSpecification& spec) 137 { 138 ostringstream res; 139 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion); 140 const char* const vtxIn = usesInout ? "in" : "attribute"; 141 const char* const vtxOut = usesInout ? "out" : "varying"; 142 143 res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n"; 144 145 // Declarations (position + attribute/varying for each input). 146 res << "precision highp float;\n"; 147 res << "precision highp int;\n"; 148 res << "\n"; 149 res << vtxIn << " highp vec4 dEQP_Position;\n"; 150 151 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++) 152 { 153 const Value& val = spec.values.inputs[ndx]; 154 const DataType basicType = val.type.getBasicType(); 155 const DataType floatType = getDataTypeFloatScalars(basicType); 156 const char* const typeStr = getDataTypeName(floatType); 157 158 res << vtxIn << " " << typeStr << " a_" << val.name << ";\n"; 159 160 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 161 res << vtxOut << " " << typeStr << " " << val.name << ";\n"; 162 else 163 res << vtxOut << " " << typeStr << " v_" << val.name << ";\n"; 164 } 165 res << "\n"; 166 167 // Main function. 168 // - gl_Position = dEQP_Position; 169 // - for each input: write attribute directly to varying 170 res << "void main()\n"; 171 res << "{\n"; 172 res << " gl_Position = dEQP_Position;\n"; 173 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++) 174 { 175 const Value& val = spec.values.inputs[ndx]; 176 const string& name = val.name; 177 178 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT) 179 res << " " << name << " = a_" << name << ";\n"; 180 else 181 res << " v_" << name << " = a_" << name << ";\n"; 182 } 183 184 res << "}\n"; 185 return res.str(); 186 } 187 188 static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName) 189 { 190 bool isFirstOutput = true; 191 192 for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++) 193 { 194 const Value& val = valueBlock.outputs[ndx]; 195 196 // Check if we're only interested in one variable (then skip if not the right one). 197 if (checkVarName && val.name != checkVarName) 198 continue; 199 200 // Prefix. 201 if (isFirstOutput) 202 { 203 output << "bool RES = "; 204 isFirstOutput = false; 205 } 206 else 207 output << "RES = RES && "; 208 209 // Generate actual comparison. 210 if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT) 211 output << "isOk(" << val.name << ", ref_" << val.name << ", 0.05);\n"; 212 else 213 output << "isOk(" << nonFloatNamePrefix << val.name << ", ref_" << val.name << ");\n"; 214 } 215 216 if (isFirstOutput) 217 output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case? 218 else 219 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n"; 220 } 221 222 static inline bool supportsFragmentHighp (glu::GLSLVersion version) 223 { 224 return version != glu::GLSL_VERSION_100_ES; 225 } 226 227 static string genFragmentShader (const ShaderCaseSpecification& spec) 228 { 229 ostringstream shader; 230 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion); 231 const bool customColorOut = usesInout; 232 const char* const fragIn = usesInout ? "in" : "varying"; 233 const char* const prec = supportsFragmentHighp(spec.targetVersion) ? "highp" : "mediump"; 234 235 shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n"; 236 237 shader << "precision " << prec << " float;\n"; 238 shader << "precision " << prec << " int;\n"; 239 shader << "\n"; 240 241 if (customColorOut) 242 { 243 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 244 shader << "\n"; 245 } 246 247 genCompareFunctions(shader, spec.values, true); 248 shader << "\n"; 249 250 // Declarations (varying, reference for each output). 251 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++) 252 { 253 const Value& val = spec.values.outputs[ndx]; 254 const DataType basicType = val.type.getBasicType(); 255 const DataType floatType = getDataTypeFloatScalars(basicType); 256 const char* const floatTypeStr = getDataTypeName(floatType); 257 const char* const refTypeStr = getDataTypeName(basicType); 258 259 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 260 shader << fragIn << " " << floatTypeStr << " " << val.name << ";\n"; 261 else 262 shader << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n"; 263 264 shader << "uniform " << refTypeStr << " ref_" << val.name << ";\n"; 265 } 266 267 shader << "\n"; 268 shader << "void main()\n"; 269 shader << "{\n"; 270 271 shader << " "; 272 genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", spec.values, "v_", DE_NULL); 273 274 shader << "}\n"; 275 return shader.str(); 276 } 277 278 // Specialize a shader for the vertex shader test case. 279 static string specializeVertexShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions) 280 { 281 ostringstream decl; 282 ostringstream setup; 283 ostringstream output; 284 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion); 285 const char* const vtxIn = usesInout ? "in" : "attribute"; 286 const char* const vtxOut = usesInout ? "out" : "varying"; 287 288 // generated from "both" case 289 DE_ASSERT(spec.caseType == CASETYPE_VERTEX_ONLY); 290 291 // Output (write out position). 292 output << "gl_Position = dEQP_Position;\n"; 293 294 // Declarations (position + attribute for each input, varying for each output). 295 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 296 297 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++) 298 { 299 const Value& val = spec.values.inputs[ndx]; 300 const DataType basicType = val.type.getBasicType(); 301 const DataType floatType = getDataTypeFloatScalars(basicType); 302 const char* const floatTypeStr = getDataTypeName(floatType); 303 const char* const refTypeStr = getDataTypeName(basicType); 304 305 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 306 { 307 decl << vtxIn << " " << floatTypeStr << " " << val.name << ";\n"; 308 } 309 else 310 { 311 decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n"; 312 setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(a_" << val.name << ");\n"; 313 } 314 } 315 316 // \todo [2015-07-24 pyry] Why are uniforms missing? 317 318 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++) 319 { 320 const Value& val = spec.values.outputs[ndx]; 321 const DataType basicType = val.type.getBasicType(); 322 const DataType floatType = getDataTypeFloatScalars(basicType); 323 const char* const floatTypeStr = getDataTypeName(floatType); 324 const char* const refTypeStr = getDataTypeName(basicType); 325 326 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 327 decl << vtxOut << " " << floatTypeStr << " " << val.name << ";\n"; 328 else 329 { 330 decl << vtxOut << " " << floatTypeStr << " v_" << val.name << ";\n"; 331 decl << refTypeStr << " " << val.name << ";\n"; 332 333 output << "v_" << val.name << " = " << floatTypeStr << "(" << val.name << ");\n"; 334 } 335 } 336 337 // Shader specialization. 338 map<string, string> params; 339 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 340 params.insert(pair<string, string>("SETUP", setup.str())); 341 params.insert(pair<string, string>("OUTPUT", output.str())); 342 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position")); 343 344 StringTemplate tmpl (src); 345 const string baseSrc = tmpl.specialize(params); 346 const string withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_VERTEX); 347 348 return withExt; 349 } 350 351 // Specialize a shader for the fragment shader test case. 352 static string specializeFragmentShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions) 353 { 354 ostringstream decl; 355 ostringstream setup; 356 ostringstream output; 357 358 const bool usesInout = glslVersionUsesInOutQualifiers(spec.targetVersion); 359 const bool customColorOut = usesInout; 360 const char* const fragIn = usesInout ? "in" : "varying"; 361 const char* const fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 362 363 // generated from "both" case 364 DE_ASSERT(spec.caseType == CASETYPE_FRAGMENT_ONLY); 365 366 genCompareFunctions(decl, spec.values, false); 367 genCompareOp(output, fragColor, spec.values, "", DE_NULL); 368 369 if (customColorOut) 370 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 371 372 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++) 373 { 374 const Value& val = spec.values.inputs[ndx]; 375 const DataType basicType = val.type.getBasicType(); 376 const DataType floatType = getDataTypeFloatScalars(basicType); 377 const char* const floatTypeStr = getDataTypeName(floatType); 378 const char* const refTypeStr = getDataTypeName(basicType); 379 380 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 381 decl << fragIn << " " << floatTypeStr << " " << val.name << ";\n"; 382 else 383 { 384 decl << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n"; 385 std::string offset = isDataTypeIntOrIVec(basicType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation 386 setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(v_" << val.name << offset << ");\n"; 387 } 388 } 389 390 // \todo [2015-07-24 pyry] Why are uniforms missing? 391 392 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++) 393 { 394 const Value& val = spec.values.outputs[ndx]; 395 const DataType basicType = val.type.getBasicType(); 396 const char* const refTypeStr = getDataTypeName(basicType); 397 398 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n"; 399 decl << refTypeStr << " " << val.name << ";\n"; 400 } 401 402 /* \todo [2010-04-01 petri] Check all outputs. */ 403 404 // Shader specialization. 405 map<string, string> params; 406 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 407 params.insert(pair<string, string>("SETUP", setup.str())); 408 params.insert(pair<string, string>("OUTPUT", output.str())); 409 params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor)); 410 411 StringTemplate tmpl (src); 412 const string baseSrc = tmpl.specialize(params); 413 const string withExt = injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_FRAGMENT); 414 415 return withExt; 416 } 417 418 static void generateUniformDeclarations (std::ostream& dst, const ValueBlock& valueBlock) 419 { 420 for (size_t ndx = 0; ndx < valueBlock.uniforms.size(); ndx++) 421 { 422 const Value& val = valueBlock.uniforms[ndx]; 423 const char* const typeStr = getDataTypeName(val.type.getBasicType()); 424 425 if (val.name.find('.') == string::npos) 426 dst << "uniform " << typeStr << " " << val.name << ";\n"; 427 } 428 } 429 430 static map<string, string> generateVertexSpecialization (const ProgramSpecializationParams& specParams) 431 { 432 const bool usesInout = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion); 433 const char* vtxIn = usesInout ? "in" : "attribute"; 434 ostringstream decl; 435 ostringstream setup; 436 map<string, string> params; 437 438 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 439 440 for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++) 441 { 442 const Value& val = specParams.caseSpec.values.inputs[ndx]; 443 const DataType basicType = val.type.getBasicType(); 444 const char* const typeStr = getDataTypeName(val.type.getBasicType()); 445 446 if (getDataTypeScalarType(basicType) == TYPE_FLOAT) 447 { 448 decl << vtxIn << " " << typeStr << " " << val.name << ";\n"; 449 } 450 else 451 { 452 const DataType floatType = getDataTypeFloatScalars(basicType); 453 const char* const floatTypeStr = getDataTypeName(floatType); 454 455 decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n"; 456 setup << typeStr << " " << val.name << " = " << typeStr << "(a_" << val.name << ");\n"; 457 } 458 } 459 460 generateUniformDeclarations(decl, specParams.caseSpec.values); 461 462 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str())); 463 params.insert(pair<string, string>("VERTEX_SETUP", setup.str())); 464 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n"))); 465 466 return params; 467 } 468 469 static map<string, string> generateFragmentSpecialization (const ProgramSpecializationParams& specParams) 470 { 471 const bool usesInout = glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion); 472 const bool customColorOut = usesInout; 473 const char* const fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 474 ostringstream decl; 475 ostringstream output; 476 map<string, string> params; 477 478 genCompareFunctions(decl, specParams.caseSpec.values, false); 479 genCompareOp(output, fragColor, specParams.caseSpec.values, "", DE_NULL); 480 481 if (customColorOut) 482 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 483 484 for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++) 485 { 486 const Value& val = specParams.caseSpec.values.outputs[ndx]; 487 const char* const refTypeStr = getDataTypeName(val.type.getBasicType()); 488 489 decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n"; 490 decl << refTypeStr << " " << val.name << ";\n"; 491 } 492 493 generateUniformDeclarations(decl, specParams.caseSpec.values); 494 495 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str())); 496 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str())); 497 params.insert(pair<string, string>("FRAG_COLOR", fragColor)); 498 499 return params; 500 } 501 502 static map<string, string> generateGeometrySpecialization (const ProgramSpecializationParams& specParams) 503 { 504 ostringstream decl; 505 map<string, string> params; 506 507 decl << "layout (triangles) in;\n"; 508 decl << "layout (triangle_strip, max_vertices=3) out;\n"; 509 decl << "\n"; 510 511 generateUniformDeclarations(decl, specParams.caseSpec.values); 512 513 params.insert(pair<string, string>("GEOMETRY_DECLARATIONS", decl.str())); 514 515 return params; 516 } 517 518 static map<string, string> generateTessControlSpecialization (const ProgramSpecializationParams& specParams) 519 { 520 ostringstream decl; 521 ostringstream output; 522 map<string, string> params; 523 524 decl << "layout (vertices=3) out;\n"; 525 decl << "\n"; 526 527 generateUniformDeclarations(decl, specParams.caseSpec.values); 528 529 output << "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 530 "gl_TessLevelInner[0] = 2.0;\n" 531 "gl_TessLevelInner[1] = 2.0;\n" 532 "gl_TessLevelOuter[0] = 2.0;\n" 533 "gl_TessLevelOuter[1] = 2.0;\n" 534 "gl_TessLevelOuter[2] = 2.0;\n" 535 "gl_TessLevelOuter[3] = 2.0;"; 536 537 params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS", decl.str())); 538 params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT", output.str())); 539 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices))); 540 541 return params; 542 } 543 544 static map<string, string> generateTessEvalSpecialization (const ProgramSpecializationParams& specParams) 545 { 546 ostringstream decl; 547 ostringstream output; 548 map<string, string> params; 549 550 decl << "layout (triangles) in;\n"; 551 decl << "\n"; 552 553 generateUniformDeclarations(decl, specParams.caseSpec.values); 554 555 output << "gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n"; 556 557 params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS", decl.str())); 558 params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT", output.str())); 559 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices))); 560 561 return params; 562 } 563 564 static void specializeShaderSources (ProgramSources& dst, 565 const ProgramSources& src, 566 const ProgramSpecializationParams& specParams, 567 glu::ShaderType shaderType, 568 map<string, string> (*specializationGenerator) (const ProgramSpecializationParams& specParams)) 569 { 570 if (!src.sources[shaderType].empty()) 571 { 572 const map<string, string> tmplParams = specializationGenerator(specParams); 573 574 for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx) 575 { 576 const StringTemplate tmpl (src.sources[shaderType][ndx]); 577 const std::string baseGLSLCode = tmpl.specialize(tmplParams); 578 const std::string sourceWithExts = injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType); 579 580 dst << glu::ShaderSource(shaderType, sourceWithExts); 581 } 582 } 583 } 584 585 static void specializeProgramSources (glu::ProgramSources& dst, 586 const glu::ProgramSources& src, 587 const ProgramSpecializationParams& specParams) 588 { 589 specializeShaderSources(dst, src, specParams, SHADERTYPE_VERTEX, generateVertexSpecialization); 590 specializeShaderSources(dst, src, specParams, SHADERTYPE_FRAGMENT, generateFragmentSpecialization); 591 specializeShaderSources(dst, src, specParams, SHADERTYPE_GEOMETRY, generateGeometrySpecialization); 592 specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_CONTROL, generateTessControlSpecialization); 593 specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_EVALUATION, generateTessEvalSpecialization); 594 595 dst << ProgramSeparable(src.separable); 596 } 597 598 enum 599 { 600 VIEWPORT_WIDTH = 128, 601 VIEWPORT_HEIGHT = 128 602 }; 603 604 class BeforeDrawValidator : public glu::DrawUtilCallback 605 { 606 public: 607 enum TargetType 608 { 609 TARGETTYPE_PROGRAM = 0, 610 TARGETTYPE_PIPELINE, 611 612 TARGETTYPE_LAST 613 }; 614 615 BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType); 616 617 void beforeDrawCall (void); 618 619 const std::string& getInfoLog (void) const; 620 glw::GLint getValidateStatus (void) const; 621 622 private: 623 const glw::Functions& m_gl; 624 const glw::GLuint m_target; 625 const TargetType m_targetType; 626 627 glw::GLint m_validateStatus; 628 std::string m_logMessage; 629 }; 630 631 BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType) 632 : m_gl (gl) 633 , m_target (target) 634 , m_targetType (targetType) 635 , m_validateStatus (-1) 636 { 637 DE_ASSERT(targetType < TARGETTYPE_LAST); 638 } 639 640 void BeforeDrawValidator::beforeDrawCall (void) 641 { 642 glw::GLint bytesWritten = 0; 643 glw::GLint infoLogLength; 644 std::vector<glw::GLchar> logBuffer; 645 int stringLength; 646 647 // validate 648 if (m_targetType == TARGETTYPE_PROGRAM) 649 m_gl.validateProgram(m_target); 650 else if (m_targetType == TARGETTYPE_PIPELINE) 651 m_gl.validateProgramPipeline(m_target); 652 else 653 DE_ASSERT(false); 654 655 GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate"); 656 657 // check status 658 m_validateStatus = -1; 659 660 if (m_targetType == TARGETTYPE_PROGRAM) 661 m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus); 662 else if (m_targetType == TARGETTYPE_PIPELINE) 663 m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus); 664 else 665 DE_ASSERT(false); 666 667 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status"); 668 TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE); 669 670 // read log 671 672 infoLogLength = 0; 673 674 if (m_targetType == TARGETTYPE_PROGRAM) 675 m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength); 676 else if (m_targetType == TARGETTYPE_PIPELINE) 677 m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength); 678 else 679 DE_ASSERT(false); 680 681 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length"); 682 683 if (infoLogLength <= 0) 684 { 685 m_logMessage.clear(); 686 return; 687 } 688 689 logBuffer.resize(infoLogLength + 2, '0'); // +1 for zero terminator (infoLogLength should include it, but better play it safe), +1 to make sure buffer is always larger 690 691 if (m_targetType == TARGETTYPE_PROGRAM) 692 m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]); 693 else if (m_targetType == TARGETTYPE_PIPELINE) 694 m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]); 695 else 696 DE_ASSERT(false); 697 698 // just ignore bytesWritten to be safe, find the null terminator 699 stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin()); 700 m_logMessage.assign(&logBuffer[0], stringLength); 701 } 702 703 const std::string& BeforeDrawValidator::getInfoLog (void) const 704 { 705 return m_logMessage; 706 } 707 708 glw::GLint BeforeDrawValidator::getValidateStatus (void) const 709 { 710 return m_validateStatus; 711 } 712 713 // ShaderCase. 714 715 ShaderLibraryCase::ShaderLibraryCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification) 716 : tcu::TestCase (testCtx, name, description) 717 , m_renderCtx (renderCtx) 718 , m_contextInfo (contextInfo) 719 , m_spec (specification) 720 { 721 } 722 723 ShaderLibraryCase::~ShaderLibraryCase (void) 724 { 725 } 726 727 void ShaderLibraryCase::init (void) 728 { 729 DE_ASSERT(isValid(m_spec)); 730 731 checkImplementationLimits(m_spec.requiredCaps, m_contextInfo); 732 733 // log the expected result 734 switch (m_spec.expectResult) 735 { 736 case EXPECT_PASS: 737 // Don't write anything 738 break; 739 740 case EXPECT_COMPILE_FAIL: 741 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage; 742 break; 743 744 case EXPECT_LINK_FAIL: 745 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage; 746 break; 747 748 case EXPECT_COMPILE_LINK_FAIL: 749 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage; 750 break; 751 752 case EXPECT_VALIDATION_FAIL: 753 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage; 754 break; 755 756 case EXPECT_BUILD_SUCCESSFUL: 757 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage; 758 break; 759 760 default: 761 DE_ASSERT(false); 762 break; 763 } 764 } 765 766 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const Value& val, int arrayNdx, tcu::TestLog& log) 767 { 768 bool foundAnyMatch = false; 769 770 for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx) 771 { 772 const DataType dataType = val.type.getBasicType(); 773 const int scalarSize = getDataTypeScalarSize(dataType); 774 const int loc = gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str()); 775 const int elemNdx = arrayNdx * scalarSize; 776 777 DE_ASSERT(elemNdx+scalarSize <= (int)val.elements.size()); 778 779 if (loc == -1) 780 continue; 781 782 foundAnyMatch = true; 783 784 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLfloat)); 785 DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLint)); 786 787 gl.useProgram(pipelinePrograms[programNdx]); 788 789 switch (dataType) 790 { 791 case TYPE_FLOAT: gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32); break; 792 case TYPE_FLOAT_VEC2: gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32); break; 793 case TYPE_FLOAT_VEC3: gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32); break; 794 case TYPE_FLOAT_VEC4: gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32); break; 795 case TYPE_FLOAT_MAT2: gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 796 case TYPE_FLOAT_MAT3: gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 797 case TYPE_FLOAT_MAT4: gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 798 case TYPE_INT: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break; 799 case TYPE_INT_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break; 800 case TYPE_INT_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break; 801 case TYPE_INT_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break; 802 case TYPE_BOOL: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break; 803 case TYPE_BOOL_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break; 804 case TYPE_BOOL_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break; 805 case TYPE_BOOL_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break; 806 case TYPE_UINT: gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 807 case TYPE_UINT_VEC2: gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 808 case TYPE_UINT_VEC3: gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 809 case TYPE_UINT_VEC4: gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 810 case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 811 case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 812 case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 813 case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 814 case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 815 case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 816 817 case TYPE_SAMPLER_2D: 818 case TYPE_SAMPLER_CUBE: 819 DE_FATAL("implement!"); 820 break; 821 822 default: 823 DE_ASSERT(false); 824 } 825 } 826 827 if (!foundAnyMatch) 828 log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage; 829 } 830 831 static bool isTessellationPresent (const ShaderCaseSpecification& spec) 832 { 833 if (spec.programs[0].sources.separable) 834 { 835 const deUint32 tessellationBits = (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | 836 (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION); 837 838 for (int programNdx = 0; programNdx < (int)spec.programs.size(); ++programNdx) 839 if (spec.programs[programNdx].activeStages & tessellationBits) 840 return true; 841 return false; 842 } 843 else 844 return !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() || 845 !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty(); 846 } 847 848 static bool isTessellationSupported (const glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo) 849 { 850 if (renderCtx.getType().getProfile() == PROFILE_ES) 851 { 852 const int majorVer = renderCtx.getType().getMajorVersion(); 853 const int minorVer = renderCtx.getType().getMinorVersion(); 854 855 return (majorVer > 3) || (majorVer == 3 && minorVer >= 2) || 856 ctxInfo.isExtensionSupported("GL_EXT_tessellation_shader"); 857 } 858 else 859 return false; 860 } 861 862 static bool checkPixels (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& surface) 863 { 864 bool allWhite = true; 865 bool allBlack = true; 866 bool anyUnexpected = false; 867 868 for (int y = 0; y < surface.getHeight(); y++) 869 { 870 for (int x = 0; x < surface.getWidth(); x++) 871 { 872 const tcu::IVec4 pixel = surface.getPixelInt(x, y); 873 // Note: we really do not want to involve alpha in the check comparison 874 // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black. 875 const bool isWhite = (pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255); 876 const bool isBlack = (pixel[0] == 0) && (pixel[1] == 0) && (pixel[2] == 0); 877 878 allWhite = allWhite && isWhite; 879 allBlack = allBlack && isBlack; 880 anyUnexpected = anyUnexpected || (!isWhite && !isBlack); 881 } 882 } 883 884 if (!allWhite) 885 { 886 if (anyUnexpected) 887 log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage; 888 else if (!allBlack) 889 log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage; 890 891 return false; 892 } 893 894 return true; 895 } 896 897 bool ShaderLibraryCase::execute (void) 898 { 899 const float quadSize = 1.0f; 900 static const float s_positions[4*4] = 901 { 902 -quadSize, -quadSize, 0.0f, 1.0f, 903 -quadSize, +quadSize, 0.0f, 1.0f, 904 +quadSize, -quadSize, 0.0f, 1.0f, 905 +quadSize, +quadSize, 0.0f, 1.0f 906 }; 907 908 static const deUint16 s_indices[2*3] = 909 { 910 0, 1, 2, 911 1, 3, 2 912 }; 913 914 TestLog& log = m_testCtx.getLog(); 915 const glw::Functions& gl = m_renderCtx.getFunctions(); 916 917 // Compute viewport. 918 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget(); 919 de::Random rnd (deStringHash(getName())); 920 const int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH); 921 const int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT); 922 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - width); 923 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - height); 924 const int numVerticesPerDraw = 4; 925 const bool tessellationPresent = isTessellationPresent(m_spec); 926 const bool separablePrograms = m_spec.programs[0].sources.separable; 927 928 bool allCompilesOk = true; 929 bool allLinksOk = true; 930 const char* failReason = DE_NULL; 931 932 vector<ProgramSources> specializedSources (m_spec.programs.size()); 933 934 deUint32 vertexProgramID = -1; 935 vector<deUint32> pipelineProgramIDs; 936 vector<SharedPtr<ShaderProgram> > programs; 937 SharedPtr<ProgramPipeline> programPipeline; 938 939 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start"); 940 941 // Specialize shaders 942 if (m_spec.caseType == CASETYPE_VERTEX_ONLY) 943 { 944 const vector<RequiredExtension> reqExt = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo); 945 946 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX].size() == 1); 947 specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX][0], reqExt)) 948 << glu::FragmentSource(genFragmentShader(m_spec)); 949 } 950 else if (m_spec.caseType == CASETYPE_FRAGMENT_ONLY) 951 { 952 const vector<RequiredExtension> reqExt = checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo); 953 954 DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].size() == 1); 955 specializedSources[0] << glu::VertexSource(genVertexShader(m_spec)) 956 << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT][0], reqExt)); 957 } 958 else 959 { 960 DE_ASSERT(m_spec.caseType == CASETYPE_COMPLETE); 961 962 const int maxPatchVertices = isTessellationPresent(m_spec) && isTessellationSupported(m_renderCtx, m_contextInfo) 963 ? m_contextInfo.getInt(GL_MAX_PATCH_VERTICES) : 0; 964 965 for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++) 966 { 967 const ProgramSpecializationParams progSpecParams (m_spec, checkAndSpecializeExtensions(m_spec.programs[progNdx].requiredExtensions, m_contextInfo), maxPatchVertices); 968 969 specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams); 970 } 971 } 972 973 if (!separablePrograms) 974 { 975 de::SharedPtr<glu::ShaderProgram> program (new glu::ShaderProgram(m_renderCtx, specializedSources[0])); 976 977 vertexProgramID = program->getProgram(); 978 pipelineProgramIDs.push_back(program->getProgram()); 979 programs.push_back(program); 980 981 // Check that compile/link results are what we expect. 982 983 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0); 984 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 985 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk) 986 allCompilesOk = false; 987 988 if (!program->getProgramInfo().linkOk) 989 allLinksOk = false; 990 991 log << *program; 992 } 993 else 994 { 995 // Separate programs 996 for (size_t programNdx = 0; programNdx < m_spec.programs.size(); ++programNdx) 997 { 998 de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, specializedSources[programNdx])); 999 1000 if (m_spec.programs[programNdx].activeStages & (1u << glu::SHADERTYPE_VERTEX)) 1001 vertexProgramID = program->getProgram(); 1002 1003 pipelineProgramIDs.push_back(program->getProgram()); 1004 programs.push_back(program); 1005 1006 // Check that compile/link results are what we expect. 1007 1008 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0); 1009 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 1010 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk) 1011 allCompilesOk = false; 1012 1013 if (!program->getProgramInfo().linkOk) 1014 allLinksOk = false; 1015 1016 // Log program and active stages 1017 { 1018 const tcu::ScopedLogSection section (log, "Program", "Program " + de::toString(programNdx+1)); 1019 tcu::MessageBuilder builder (&log); 1020 bool firstStage = true; 1021 1022 builder << "Pipeline uses stages: "; 1023 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 1024 { 1025 if (m_spec.programs[programNdx].activeStages & (1u << stage)) 1026 { 1027 if (!firstStage) 1028 builder << ", "; 1029 builder << glu::getShaderTypeName((glu::ShaderType)stage); 1030 firstStage = true; 1031 } 1032 } 1033 builder << tcu::TestLog::EndMessage; 1034 1035 log << *program; 1036 } 1037 } 1038 } 1039 1040 switch (m_spec.expectResult) 1041 { 1042 case EXPECT_PASS: 1043 case EXPECT_VALIDATION_FAIL: 1044 case EXPECT_BUILD_SUCCESSFUL: 1045 if (!allCompilesOk) 1046 failReason = "expected shaders to compile and link properly, but failed to compile."; 1047 else if (!allLinksOk) 1048 failReason = "expected shaders to compile and link properly, but failed to link."; 1049 break; 1050 1051 case EXPECT_COMPILE_FAIL: 1052 if (allCompilesOk && !allLinksOk) 1053 failReason = "expected compilation to fail, but shaders compiled and link failed."; 1054 else if (allCompilesOk) 1055 failReason = "expected compilation to fail, but shaders compiled correctly."; 1056 break; 1057 1058 case EXPECT_LINK_FAIL: 1059 if (!allCompilesOk) 1060 failReason = "expected linking to fail, but unable to compile."; 1061 else if (allLinksOk) 1062 failReason = "expected linking to fail, but passed."; 1063 break; 1064 1065 case EXPECT_COMPILE_LINK_FAIL: 1066 if (allCompilesOk && allLinksOk) 1067 failReason = "expected compile or link to fail, but passed."; 1068 break; 1069 1070 default: 1071 DE_ASSERT(false); 1072 return false; 1073 } 1074 1075 if (failReason != DE_NULL) 1076 { 1077 // \todo [2010-06-07 petri] These should be handled in the test case? 1078 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage; 1079 1080 if (m_spec.fullGLSLES100Required) 1081 { 1082 log << TestLog::Message 1083 << "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required." 1084 << TestLog::EndMessage; 1085 1086 if (allCompilesOk && !allLinksOk) 1087 { 1088 // Used features are detectable at compile time. If implementation parses shader 1089 // at link time, report it as quality warning. 1090 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason); 1091 } 1092 else 1093 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported"); 1094 } 1095 else if (m_spec.expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk) 1096 { 1097 // If implementation parses shader at link time, report it as quality warning. 1098 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason); 1099 } 1100 else 1101 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason); 1102 return false; 1103 } 1104 1105 // Return if shader is not intended to be run 1106 if (m_spec.expectResult == EXPECT_COMPILE_FAIL || 1107 m_spec.expectResult == EXPECT_COMPILE_LINK_FAIL || 1108 m_spec.expectResult == EXPECT_LINK_FAIL || 1109 m_spec.expectResult == EXPECT_BUILD_SUCCESSFUL) 1110 return true; 1111 1112 // Setup viewport. 1113 gl.viewport(viewportX, viewportY, width, height); 1114 1115 if (separablePrograms) 1116 { 1117 programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx)); 1118 1119 // Setup pipeline 1120 gl.bindProgramPipeline(programPipeline->getPipeline()); 1121 for (int programNdx = 0; programNdx < (int)m_spec.programs.size(); ++programNdx) 1122 { 1123 deUint32 shaderFlags = 0; 1124 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 1125 if (m_spec.programs[programNdx].activeStages & (1u << stage)) 1126 shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage); 1127 1128 programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]); 1129 } 1130 1131 programPipeline->activeShaderProgram(vertexProgramID); 1132 GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline"); 1133 } 1134 else 1135 { 1136 // Start using program 1137 gl.useProgram(vertexProgramID); 1138 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()"); 1139 } 1140 1141 // Fetch location for positions positions. 1142 int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position"); 1143 if (positionLoc == -1) 1144 { 1145 string errStr = string("no location found for attribute 'dEQP_Position'"); 1146 TCU_FAIL(errStr.c_str()); 1147 } 1148 1149 // Iterate all value blocks. 1150 { 1151 const ValueBlock& valueBlock = m_spec.values; 1152 1153 // always render at least one pass even if there is no input/output data 1154 const int numRenderPasses = valueBlock.outputs.empty() ? 1 : (int)valueBlock.outputs[0].elements.size() / valueBlock.outputs[0].type.getScalarSize(); 1155 1156 // Iterate all array sub-cases. 1157 for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++) 1158 { 1159 vector<VertexArrayBinding> vertexArrays; 1160 int attribValueNdx = 0; 1161 vector<vector<float> > attribValues (valueBlock.inputs.size()); 1162 glw::GLenum postDrawError; 1163 BeforeDrawValidator beforeDrawValidator (gl, 1164 (separablePrograms) ? (programPipeline->getPipeline()) : (vertexProgramID), 1165 (separablePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE) : (BeforeDrawValidator::TARGETTYPE_PROGRAM)); 1166 1167 vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0])); 1168 1169 // Collect VA pointer for inputs 1170 for (size_t valNdx = 0; valNdx < valueBlock.inputs.size(); valNdx++) 1171 { 1172 const Value& val = valueBlock.inputs[valNdx]; 1173 const char* const valueName = val.name.c_str(); 1174 const DataType dataType = val.type.getBasicType(); 1175 const int scalarSize = getDataTypeScalarSize(dataType); 1176 1177 // Replicate values four times. 1178 std::vector<float>& scalars = attribValues[attribValueNdx++]; 1179 scalars.resize(numVerticesPerDraw * scalarSize); 1180 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType)) 1181 { 1182 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 1183 for (int ndx = 0; ndx < scalarSize; ndx++) 1184 scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32; 1185 } 1186 else 1187 { 1188 // convert to floats. 1189 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 1190 { 1191 for (int ndx = 0; ndx < scalarSize; ndx++) 1192 { 1193 float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32; 1194 DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v); 1195 scalars[repNdx*scalarSize + ndx] = v; 1196 } 1197 } 1198 } 1199 1200 // Attribute name prefix. 1201 string attribPrefix = ""; 1202 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)? 1203 if ((m_spec.caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT)) 1204 attribPrefix = "a_"; 1205 1206 // Input always given as attribute. 1207 string attribName = attribPrefix + valueName; 1208 int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str()); 1209 if (attribLoc == -1) 1210 { 1211 log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage; 1212 continue; 1213 } 1214 1215 if (isDataTypeMatrix(dataType)) 1216 { 1217 int numCols = getDataTypeMatrixNumColumns(dataType); 1218 int numRows = getDataTypeMatrixNumRows(dataType); 1219 DE_ASSERT(scalarSize == numCols*numRows); 1220 1221 for (int i = 0; i < numCols; i++) 1222 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*(int)sizeof(float), &scalars[i * numRows])); 1223 } 1224 else 1225 { 1226 DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType)); 1227 vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0])); 1228 } 1229 1230 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array"); 1231 } 1232 1233 GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms"); 1234 1235 // set reference values for outputs. 1236 for (size_t valNdx = 0; valNdx < valueBlock.outputs.size(); valNdx++) 1237 { 1238 const Value& val = valueBlock.outputs[valNdx]; 1239 const char* const valueName = val.name.c_str(); 1240 1241 // Set reference value. 1242 string refName = string("ref_") + valueName; 1243 setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog()); 1244 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms"); 1245 } 1246 1247 // set uniform values 1248 for (size_t valNdx = 0; valNdx < valueBlock.uniforms.size(); valNdx++) 1249 { 1250 const Value& val = valueBlock.uniforms[valNdx]; 1251 const char* const valueName = val.name.c_str(); 1252 1253 setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog()); 1254 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms"); 1255 } 1256 1257 // Clear. 1258 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f); 1259 gl.clear(GL_COLOR_BUFFER_BIT); 1260 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer"); 1261 1262 // Use program or pipeline 1263 if (separablePrograms) 1264 gl.useProgram(0); 1265 else 1266 gl.useProgram(vertexProgramID); 1267 1268 // Draw. 1269 if (tessellationPresent) 1270 { 1271 gl.patchParameteri(GL_PATCH_VERTICES, 3); 1272 GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)"); 1273 } 1274 1275 draw(m_renderCtx, 1276 vertexProgramID, 1277 (int)vertexArrays.size(), 1278 &vertexArrays[0], 1279 (tessellationPresent) ? 1280 (pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) : 1281 (pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])), 1282 (m_spec.expectResult == EXPECT_VALIDATION_FAIL) ? 1283 (&beforeDrawValidator) : 1284 (DE_NULL)); 1285 1286 postDrawError = gl.getError(); 1287 1288 if (m_spec.expectResult == EXPECT_PASS) 1289 { 1290 // Read back results. 1291 Surface surface (width, height); 1292 const float w = s_positions[3]; 1293 const int minY = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f); 1294 const int maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f); 1295 const int minX = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f); 1296 const int maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f); 1297 1298 GLU_EXPECT_NO_ERROR(postDrawError, "draw"); 1299 1300 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess()); 1301 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 1302 1303 if (!checkPixels(log, tcu::getSubregion(surface.getAccess(), minX, minY, maxX-minX+1, maxY-minY+1))) 1304 { 1305 log << TestLog::Message << "INCORRECT RESULT for sub-case " << arrayNdx+1 << " of " << numRenderPasses << "):" 1306 << TestLog::EndMessage; 1307 1308 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage; 1309 dumpValues(log, valueBlock, arrayNdx); 1310 1311 // Dump image on failure. 1312 log << TestLog::Image("Result", "Rendered result image", surface); 1313 1314 gl.useProgram(0); 1315 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 1316 return false; 1317 } 1318 } 1319 else if (m_spec.expectResult == EXPECT_VALIDATION_FAIL) 1320 { 1321 log << TestLog::Message 1322 << "Draw call generated error: " 1323 << glu::getErrorStr(postDrawError) << " " 1324 << ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n" 1325 << "Validate status: " 1326 << glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " " 1327 << ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n" 1328 << "Info log: " 1329 << ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n" 1330 << TestLog::EndMessage; 1331 1332 // test result 1333 1334 if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION) 1335 { 1336 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str()); 1337 return false; 1338 } 1339 1340 if (beforeDrawValidator.getValidateStatus() == GL_TRUE) 1341 { 1342 if (postDrawError == GL_NO_ERROR) 1343 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded"); 1344 else if (postDrawError == GL_INVALID_OPERATION) 1345 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)"); 1346 else 1347 DE_ASSERT(false); 1348 return false; 1349 } 1350 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR) 1351 { 1352 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)"); 1353 return false; 1354 } 1355 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION) 1356 { 1357 // Validation does not depend on input values, no need to test all values 1358 return true; 1359 } 1360 else 1361 DE_ASSERT(false); 1362 } 1363 else 1364 DE_ASSERT(false); 1365 } 1366 } 1367 1368 gl.useProgram(0); 1369 if (separablePrograms) 1370 gl.bindProgramPipeline(0); 1371 1372 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end"); 1373 return true; 1374 } 1375 1376 TestCase::IterateResult ShaderLibraryCase::iterate (void) 1377 { 1378 // Initialize state to pass. 1379 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1380 1381 bool executeOk = execute(); 1382 1383 DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); 1384 DE_UNREF(executeOk); 1385 return TestCase::STOP; 1386 } 1387 1388 } // gls 1389 } // deqp 1390