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