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 29 #include "tcuStringTemplate.hpp" 30 #include "gluShaderProgram.hpp" 31 #include "gluPixelTransfer.hpp" 32 #include "gluDrawUtil.hpp" 33 #include "gluContextInfo.hpp" 34 #include "gluStrUtil.hpp" 35 36 #include "glwFunctions.hpp" 37 #include "glwEnums.hpp" 38 39 #include "deRandom.hpp" 40 #include "deInt32.h" 41 #include "deMath.h" 42 #include "deString.h" 43 #include "deStringUtil.hpp" 44 #include "deSharedPtr.hpp" 45 46 #include <map> 47 #include <vector> 48 #include <string> 49 #include <sstream> 50 51 using namespace std; 52 using namespace tcu; 53 using namespace glu; 54 55 namespace deqp 56 { 57 namespace gls 58 { 59 namespace sl 60 { 61 62 enum 63 { 64 VIEWPORT_WIDTH = 128, 65 VIEWPORT_HEIGHT = 128 66 }; 67 68 static inline bool usesShaderInoutQualifiers (glu::GLSLVersion version) 69 { 70 switch (version) 71 { 72 case glu::GLSL_VERSION_100_ES: 73 case glu::GLSL_VERSION_130: 74 case glu::GLSL_VERSION_140: 75 case glu::GLSL_VERSION_150: 76 return false; 77 78 default: 79 return true; 80 } 81 } 82 83 static inline bool supportsFragmentHighp (glu::GLSLVersion version) 84 { 85 return version != glu::GLSL_VERSION_100_ES; 86 } 87 88 ShaderCase::ValueBlock::ValueBlock (void) 89 : arrayLength(0) 90 { 91 } 92 93 ShaderCase::CaseRequirement::CaseRequirement (void) 94 : m_type (REQUIREMENTTYPE_LAST) 95 , m_supportedExtensionNdx (-1) 96 , m_effectiveShaderStageFlags (-1) 97 , m_enumName (-1) 98 , m_referenceValue (-1) 99 { 100 } 101 102 ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createAnyExtensionRequirement (const std::vector<std::string>& requirements, deUint32 effectiveShaderStageFlags) 103 { 104 CaseRequirement retVal; 105 106 retVal.m_type = REQUIREMENTTYPE_EXTENSION; 107 retVal.m_extensions = requirements; 108 retVal.m_effectiveShaderStageFlags = effectiveShaderStageFlags; 109 110 return retVal; 111 } 112 113 ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createLimitRequirement (deUint32 enumName, int ref) 114 { 115 CaseRequirement retVal; 116 117 retVal.m_type = REQUIREMENTTYPE_IMPLEMENTATION_LIMIT; 118 retVal.m_enumName = enumName; 119 retVal.m_referenceValue = ref; 120 121 return retVal; 122 } 123 124 void ShaderCase::CaseRequirement::checkRequirements (glu::RenderContext& renderCtx, const glu::ContextInfo& contextInfo) 125 { 126 DE_UNREF(renderCtx); 127 128 switch (m_type) 129 { 130 case REQUIREMENTTYPE_EXTENSION: 131 { 132 for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx) 133 { 134 if (contextInfo.isExtensionSupported(m_extensions[ndx].c_str())) 135 { 136 m_supportedExtensionNdx = ndx; 137 return; 138 } 139 } 140 141 // no extension(s). Make a nice output 142 { 143 std::ostringstream extensionList; 144 145 for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx) 146 { 147 if (!extensionList.str().empty()) 148 extensionList << ", "; 149 extensionList << m_extensions[ndx]; 150 } 151 152 if (m_extensions.size() == 1) 153 throw tcu::NotSupportedError("Test requires extension " + extensionList.str()); 154 else 155 throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str()); 156 } 157 158 // cannot be reached 159 } 160 161 case REQUIREMENTTYPE_IMPLEMENTATION_LIMIT: 162 { 163 const glw::Functions& gl = renderCtx.getFunctions(); 164 glw::GLint value = 0; 165 glw::GLenum error; 166 167 gl.getIntegerv(m_enumName, &value); 168 error = gl.getError(); 169 170 if (error != GL_NO_ERROR) 171 throw tcu::TestError("Query for " + de::toString(glu::getGettableStateStr(m_enumName)) + " generated " + de::toString(glu::getErrorStr(error))); 172 173 if (!(value > m_referenceValue)) 174 throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(m_enumName)) + " (" + de::toString(value) + ") > " + de::toString(m_referenceValue)); 175 176 return; 177 } 178 179 default: 180 DE_ASSERT(false); 181 } 182 } 183 184 ShaderCase::ShaderCaseSpecification::ShaderCaseSpecification (void) 185 : expectResult (EXPECT_LAST) 186 , targetVersion (glu::GLSL_VERSION_LAST) 187 , caseType (CASETYPE_COMPLETE) 188 { 189 } 190 191 ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource) 192 { 193 ShaderCaseSpecification retVal; 194 retVal.expectResult = expectResult_; 195 retVal.targetVersion = targetVersion_; 196 retVal.caseType = CASETYPE_VERTEX_ONLY; 197 retVal.valueBlocks = values; 198 retVal.vertexSources.push_back(sharedSource); 199 return retVal; 200 } 201 202 ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource) 203 { 204 ShaderCaseSpecification retVal; 205 retVal.expectResult = expectResult_; 206 retVal.targetVersion = targetVersion_; 207 retVal.caseType = CASETYPE_FRAGMENT_ONLY; 208 retVal.valueBlocks = values; 209 retVal.fragmentSources.push_back(sharedSource); 210 return retVal; 211 } 212 213 class BeforeDrawValidator : public glu::DrawUtilCallback 214 { 215 public: 216 enum TargetType 217 { 218 TARGETTYPE_PROGRAM = 0, 219 TARGETTYPE_PIPELINE, 220 221 TARGETTYPE_LAST 222 }; 223 224 BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType); 225 226 void beforeDrawCall (void); 227 228 const std::string& getInfoLog (void) const; 229 glw::GLint getValidateStatus (void) const; 230 231 private: 232 const glw::Functions& m_gl; 233 const glw::GLuint m_target; 234 const TargetType m_targetType; 235 236 glw::GLint m_validateStatus; 237 std::string m_logMessage; 238 }; 239 240 BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType) 241 : m_gl (gl) 242 , m_target (target) 243 , m_targetType (targetType) 244 , m_validateStatus (-1) 245 { 246 DE_ASSERT(targetType < TARGETTYPE_LAST); 247 } 248 249 void BeforeDrawValidator::beforeDrawCall (void) 250 { 251 glw::GLint bytesWritten = 0; 252 glw::GLint infoLogLength; 253 std::vector<glw::GLchar> logBuffer; 254 int stringLength; 255 256 // validate 257 if (m_targetType == TARGETTYPE_PROGRAM) 258 m_gl.validateProgram(m_target); 259 else if (m_targetType == TARGETTYPE_PIPELINE) 260 m_gl.validateProgramPipeline(m_target); 261 else 262 DE_ASSERT(false); 263 264 GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate"); 265 266 // check status 267 m_validateStatus = -1; 268 269 if (m_targetType == TARGETTYPE_PROGRAM) 270 m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus); 271 else if (m_targetType == TARGETTYPE_PIPELINE) 272 m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus); 273 else 274 DE_ASSERT(false); 275 276 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status"); 277 TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE); 278 279 // read log 280 281 infoLogLength = 0; 282 283 if (m_targetType == TARGETTYPE_PROGRAM) 284 m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength); 285 else if (m_targetType == TARGETTYPE_PIPELINE) 286 m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength); 287 else 288 DE_ASSERT(false); 289 290 GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length"); 291 292 if (infoLogLength <= 0) 293 { 294 m_logMessage.clear(); 295 return; 296 } 297 298 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 299 300 if (m_targetType == TARGETTYPE_PROGRAM) 301 m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]); 302 else if (m_targetType == TARGETTYPE_PIPELINE) 303 m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]); 304 else 305 DE_ASSERT(false); 306 307 // just ignore bytesWritten to be safe, find the null terminator 308 stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin()); 309 m_logMessage.assign(&logBuffer[0], stringLength); 310 } 311 312 const std::string& BeforeDrawValidator::getInfoLog (void) const 313 { 314 return m_logMessage; 315 } 316 317 glw::GLint BeforeDrawValidator::getValidateStatus (void) const 318 { 319 return m_validateStatus; 320 } 321 322 // ShaderCase. 323 324 ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification) 325 : tcu::TestCase (testCtx, name, description) 326 , m_renderCtx (renderCtx) 327 , m_contextInfo (contextInfo) 328 , m_caseType (specification.caseType) 329 , m_expectResult (specification.expectResult) 330 , m_targetVersion (specification.targetVersion) 331 , m_separatePrograms (false) 332 , m_valueBlocks (specification.valueBlocks) 333 { 334 if (m_caseType == CASETYPE_VERTEX_ONLY) 335 { 336 // case generated from "both" target, vertex case 337 DE_ASSERT(specification.vertexSources.size() == 1); 338 DE_ASSERT(specification.fragmentSources.empty()); 339 DE_ASSERT(specification.tessCtrlSources.empty()); 340 DE_ASSERT(specification.tessEvalSources.empty()); 341 DE_ASSERT(specification.geometrySources.empty()); 342 } 343 else if (m_caseType == CASETYPE_FRAGMENT_ONLY) 344 { 345 // case generated from "both" target, fragment case 346 DE_ASSERT(specification.vertexSources.empty()); 347 DE_ASSERT(specification.fragmentSources.size() == 1); 348 DE_ASSERT(specification.tessCtrlSources.empty()); 349 DE_ASSERT(specification.tessEvalSources.empty()); 350 DE_ASSERT(specification.geometrySources.empty()); 351 } 352 353 // single program object 354 { 355 ProgramObject program; 356 program.spec.requirements = specification.requirements; 357 program.spec.vertexSources = specification.vertexSources; 358 program.spec.fragmentSources = specification.fragmentSources; 359 program.spec.tessCtrlSources = specification.tessCtrlSources; 360 program.spec.tessEvalSources = specification.tessEvalSources; 361 program.spec.geometrySources = specification.geometrySources; 362 363 m_programs.push_back(program); 364 } 365 } 366 367 ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const PipelineCaseSpecification& specification) 368 : tcu::TestCase (testCtx, name, description) 369 , m_renderCtx (renderCtx) 370 , m_contextInfo (contextInfo) 371 , m_caseType (specification.caseType) 372 , m_expectResult (specification.expectResult) 373 , m_targetVersion (specification.targetVersion) 374 , m_separatePrograms (true) 375 , m_valueBlocks (specification.valueBlocks) 376 { 377 deUint32 totalActiveMask = 0; 378 379 DE_ASSERT(m_caseType == CASETYPE_COMPLETE); 380 381 // validate 382 383 for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx) 384 { 385 // program with an active stage must contain executable code for that stage 386 DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_VERTEX)) == 0) || !specification.programs[pipelineProgramNdx].vertexSources.empty()); 387 DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_FRAGMENT)) == 0) || !specification.programs[pipelineProgramNdx].fragmentSources.empty()); 388 DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_CONTROL)) == 0) || !specification.programs[pipelineProgramNdx].tessCtrlSources.empty()); 389 DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION)) == 0) || !specification.programs[pipelineProgramNdx].tessEvalSources.empty()); 390 DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_GEOMETRY)) == 0) || !specification.programs[pipelineProgramNdx].geometrySources.empty()); 391 392 // no two programs with with the same stage active 393 DE_ASSERT((totalActiveMask & specification.programs[pipelineProgramNdx].activeStageBits) == 0); 394 totalActiveMask |= specification.programs[pipelineProgramNdx].activeStageBits; 395 } 396 397 // create ProgramObjects 398 399 for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx) 400 { 401 ProgramObject program; 402 program.spec = specification.programs[pipelineProgramNdx]; 403 m_programs.push_back(program); 404 } 405 } 406 407 ShaderCase::~ShaderCase (void) 408 { 409 } 410 411 void ShaderCase::init (void) 412 { 413 // If no value blocks given, use an empty one. 414 if (m_valueBlocks.empty()) 415 m_valueBlocks.push_back(ValueBlock()); 416 417 // Use first value block to specialize shaders. 418 const ValueBlock& valueBlock = m_valueBlocks[0]; 419 420 // \todo [2010-04-01 petri] Check that all value blocks have matching values. 421 422 // prepare programs 423 for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx) 424 { 425 // Check requirements 426 for (int ndx = 0; ndx < (int)m_programs[programNdx].spec.requirements.size(); ++ndx) 427 m_programs[programNdx].spec.requirements[ndx].checkRequirements(m_renderCtx, m_contextInfo); 428 429 // Generate specialized shader sources. 430 if (m_caseType == CASETYPE_COMPLETE) 431 { 432 // all shaders specified separately 433 specializeVertexShaders (m_programs[programNdx].programSources, m_programs[programNdx].spec.vertexSources, valueBlock, m_programs[programNdx].spec.requirements); 434 specializeFragmentShaders (m_programs[programNdx].programSources, m_programs[programNdx].spec.fragmentSources, valueBlock, m_programs[programNdx].spec.requirements); 435 specializeGeometryShaders (m_programs[programNdx].programSources, m_programs[programNdx].spec.geometrySources, valueBlock, m_programs[programNdx].spec.requirements); 436 specializeTessControlShaders(m_programs[programNdx].programSources, m_programs[programNdx].spec.tessCtrlSources, valueBlock, m_programs[programNdx].spec.requirements); 437 specializeTessEvalShaders (m_programs[programNdx].programSources, m_programs[programNdx].spec.tessEvalSources, valueBlock, m_programs[programNdx].spec.requirements); 438 } 439 else if (m_caseType == CASETYPE_VERTEX_ONLY) 440 { 441 DE_ASSERT(m_programs.size() == 1); 442 DE_ASSERT(!m_separatePrograms); 443 444 // case generated from "both" target, vertex case 445 m_programs[0].programSources << glu::VertexSource(specializeVertexShader(m_programs[0].spec.vertexSources[0].c_str(), valueBlock)); 446 m_programs[0].programSources << glu::FragmentSource(genFragmentShader(valueBlock)); 447 } 448 else if (m_caseType == CASETYPE_FRAGMENT_ONLY) 449 { 450 DE_ASSERT(m_programs.size() == 1); 451 DE_ASSERT(!m_separatePrograms); 452 453 // case generated from "both" target, fragment case 454 m_programs[0].programSources << glu::VertexSource(genVertexShader(valueBlock)); 455 m_programs[0].programSources << glu::FragmentSource(specializeFragmentShader(m_programs[0].spec.fragmentSources[0].c_str(), valueBlock)); 456 } 457 458 m_programs[programNdx].programSources << glu::ProgramSeparable(m_separatePrograms); 459 } 460 461 // log the expected result 462 switch (m_expectResult) 463 { 464 case EXPECT_PASS: 465 // Don't write anything 466 break; 467 468 case EXPECT_COMPILE_FAIL: 469 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage; 470 break; 471 472 case EXPECT_LINK_FAIL: 473 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage; 474 break; 475 476 case EXPECT_COMPILE_LINK_FAIL: 477 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage; 478 break; 479 480 case EXPECT_VALIDATION_FAIL: 481 m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage; 482 break; 483 484 default: 485 DE_ASSERT(false); 486 break; 487 } 488 } 489 490 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const ShaderCase::Value& val, int arrayNdx, tcu::TestLog& log) 491 { 492 bool foundAnyMatch = false; 493 494 for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx) 495 { 496 const int scalarSize = getDataTypeScalarSize(val.dataType); 497 const int loc = gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str()); 498 const int elemNdx = (val.arrayLength == 1) ? (0) : (arrayNdx * scalarSize); 499 500 if (loc == -1) 501 continue; 502 503 foundAnyMatch = true; 504 505 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat)); 506 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint)); 507 508 gl.useProgram(pipelinePrograms[programNdx]); 509 510 switch (val.dataType) 511 { 512 case TYPE_FLOAT: gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32); break; 513 case TYPE_FLOAT_VEC2: gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32); break; 514 case TYPE_FLOAT_VEC3: gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32); break; 515 case TYPE_FLOAT_VEC4: gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32); break; 516 case TYPE_FLOAT_MAT2: gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 517 case TYPE_FLOAT_MAT3: gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 518 case TYPE_FLOAT_MAT4: gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 519 case TYPE_INT: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break; 520 case TYPE_INT_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break; 521 case TYPE_INT_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break; 522 case TYPE_INT_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break; 523 case TYPE_BOOL: gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); break; 524 case TYPE_BOOL_VEC2: gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); break; 525 case TYPE_BOOL_VEC3: gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); break; 526 case TYPE_BOOL_VEC4: gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); break; 527 case TYPE_UINT: gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 528 case TYPE_UINT_VEC2: gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 529 case TYPE_UINT_VEC3: gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 530 case TYPE_UINT_VEC4: gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); break; 531 case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 532 case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 533 case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 534 case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 535 case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 536 case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); break; 537 538 case TYPE_SAMPLER_2D: 539 case TYPE_SAMPLER_CUBE: 540 DE_ASSERT(!"implement!"); 541 break; 542 543 default: 544 DE_ASSERT(false); 545 } 546 } 547 548 if (!foundAnyMatch) 549 log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage; 550 } 551 552 bool ShaderCase::isTessellationPresent (void) const 553 { 554 if (m_separatePrograms) 555 { 556 const deUint32 tessellationBits = (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | 557 (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION); 558 559 for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx) 560 if (m_programs[programNdx].spec.activeStageBits & tessellationBits) 561 return true; 562 return false; 563 } 564 else 565 return !m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() || 566 !m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty(); 567 } 568 569 bool ShaderCase::checkPixels (Surface& surface, int minX, int maxX, int minY, int maxY) 570 { 571 TestLog& log = m_testCtx.getLog(); 572 bool allWhite = true; 573 bool allBlack = true; 574 bool anyUnexpected = false; 575 576 DE_ASSERT((maxX > minX) && (maxY > minY)); 577 578 for (int y = minY; y <= maxY; y++) 579 { 580 for (int x = minX; x <= maxX; x++) 581 { 582 RGBA pixel = surface.getPixel(x, y); 583 // Note: we really do not want to involve alpha in the check comparison 584 // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black. 585 bool isWhite = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255); 586 bool isBlack = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0); 587 588 allWhite = allWhite && isWhite; 589 allBlack = allBlack && isBlack; 590 anyUnexpected = anyUnexpected || (!isWhite && !isBlack); 591 } 592 } 593 594 if (!allWhite) 595 { 596 if (anyUnexpected) 597 log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage; 598 else if (!allBlack) 599 log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage; 600 601 return false; 602 } 603 return true; 604 } 605 606 bool ShaderCase::execute (void) 607 { 608 const float quadSize = 1.0f; 609 static const float s_positions[4*4] = 610 { 611 -quadSize, -quadSize, 0.0f, 1.0f, 612 -quadSize, +quadSize, 0.0f, 1.0f, 613 +quadSize, -quadSize, 0.0f, 1.0f, 614 +quadSize, +quadSize, 0.0f, 1.0f 615 }; 616 617 static const deUint16 s_indices[2*3] = 618 { 619 0, 1, 2, 620 1, 3, 2 621 }; 622 623 TestLog& log = m_testCtx.getLog(); 624 const glw::Functions& gl = m_renderCtx.getFunctions(); 625 626 // Compute viewport. 627 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget(); 628 de::Random rnd (deStringHash(getName())); 629 const int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH); 630 const int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT); 631 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - width); 632 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - height); 633 const int numVerticesPerDraw = 4; 634 const bool tessellationPresent = isTessellationPresent(); 635 636 bool allCompilesOk = true; 637 bool allLinksOk = true; 638 const char* failReason = DE_NULL; 639 640 deUint32 vertexProgramID = -1; 641 std::vector<deUint32> pipelineProgramIDs; 642 std::vector<de::SharedPtr<glu::ShaderProgram> > programs; 643 de::SharedPtr<glu::ProgramPipeline> programPipeline; 644 645 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start"); 646 647 if (!m_separatePrograms) 648 { 649 de::SharedPtr<glu::ShaderProgram> program (new glu::ShaderProgram(m_renderCtx, m_programs[0].programSources)); 650 651 vertexProgramID = program->getProgram(); 652 pipelineProgramIDs.push_back(program->getProgram()); 653 programs.push_back(program); 654 655 // Check that compile/link results are what we expect. 656 657 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0); 658 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 659 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk) 660 allCompilesOk = false; 661 662 if (!program->getProgramInfo().linkOk) 663 allLinksOk = false; 664 665 log << *program; 666 } 667 else 668 { 669 // Separate programs 670 for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx) 671 { 672 de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, m_programs[programNdx].programSources)); 673 674 if (m_programs[programNdx].spec.activeStageBits & (1 << glu::SHADERTYPE_VERTEX)) 675 vertexProgramID = program->getProgram(); 676 677 pipelineProgramIDs.push_back(program->getProgram()); 678 programs.push_back(program); 679 680 // Check that compile/link results are what we expect. 681 682 DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0); 683 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 684 if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk) 685 allCompilesOk = false; 686 687 if (!program->getProgramInfo().linkOk) 688 allLinksOk = false; 689 690 // Log program and active stages 691 { 692 const tcu::ScopedLogSection section (log, "Program", "Program " + de::toString(programNdx+1)); 693 tcu::MessageBuilder builder (&log); 694 bool firstStage = true; 695 696 builder << "Pipeline uses stages: "; 697 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 698 { 699 if (m_programs[programNdx].spec.activeStageBits & (1 << stage)) 700 { 701 if (!firstStage) 702 builder << ", "; 703 builder << glu::getShaderTypeName((glu::ShaderType)stage); 704 firstStage = true; 705 } 706 } 707 builder << tcu::TestLog::EndMessage; 708 709 log << *program; 710 } 711 } 712 } 713 714 switch (m_expectResult) 715 { 716 case EXPECT_PASS: 717 case EXPECT_VALIDATION_FAIL: 718 if (!allCompilesOk) 719 failReason = "expected shaders to compile and link properly, but failed to compile."; 720 else if (!allLinksOk) 721 failReason = "expected shaders to compile and link properly, but failed to link."; 722 break; 723 724 case EXPECT_COMPILE_FAIL: 725 if (allCompilesOk && !allLinksOk) 726 failReason = "expected compilation to fail, but shaders compiled and link failed."; 727 else if (allCompilesOk) 728 failReason = "expected compilation to fail, but shaders compiled correctly."; 729 break; 730 731 case EXPECT_LINK_FAIL: 732 if (!allCompilesOk) 733 failReason = "expected linking to fail, but unable to compile."; 734 else if (allLinksOk) 735 failReason = "expected linking to fail, but passed."; 736 break; 737 738 case EXPECT_COMPILE_LINK_FAIL: 739 if (allCompilesOk && allLinksOk) 740 failReason = "expected compile or link to fail, but passed."; 741 break; 742 743 default: 744 DE_ASSERT(false); 745 return false; 746 } 747 748 if (failReason != DE_NULL) 749 { 750 // \todo [2010-06-07 petri] These should be handled in the test case? 751 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage; 752 753 // If implementation parses shader at link time, report it as quality warning. 754 if (m_expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk) 755 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason); 756 else 757 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason); 758 return false; 759 } 760 761 // Return if compile/link expected to fail. 762 if (m_expectResult == EXPECT_COMPILE_FAIL || 763 m_expectResult == EXPECT_COMPILE_LINK_FAIL || 764 m_expectResult == EXPECT_LINK_FAIL) 765 return (failReason == DE_NULL); 766 767 // Setup viewport. 768 gl.viewport(viewportX, viewportY, width, height); 769 770 if (m_separatePrograms) 771 { 772 programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx)); 773 774 // Setup pipeline 775 gl.bindProgramPipeline(programPipeline->getPipeline()); 776 for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx) 777 { 778 deUint32 shaderFlags = 0; 779 for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage) 780 if (m_programs[programNdx].spec.activeStageBits & (1 << stage)) 781 shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage); 782 783 programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]); 784 } 785 786 programPipeline->activeShaderProgram(vertexProgramID); 787 GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline"); 788 } 789 else 790 { 791 // Start using program 792 gl.useProgram(vertexProgramID); 793 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()"); 794 } 795 796 // Fetch location for positions positions. 797 int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position"); 798 if (positionLoc == -1) 799 { 800 string errStr = string("no location found for attribute 'dEQP_Position'"); 801 TCU_FAIL(errStr.c_str()); 802 } 803 804 // Iterate all value blocks. 805 for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++) 806 { 807 const ValueBlock& valueBlock = m_valueBlocks[blockNdx]; 808 809 // always render at least one pass even if there is no input/output data 810 const int numRenderPasses = (valueBlock.arrayLength == 0) ? (1) : (valueBlock.arrayLength); 811 812 // Iterate all array sub-cases. 813 for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++) 814 { 815 int numValues = (int)valueBlock.values.size(); 816 vector<VertexArrayBinding> vertexArrays; 817 int attribValueNdx = 0; 818 vector<vector<float> > attribValues (numValues); 819 glw::GLenum postDrawError; 820 BeforeDrawValidator beforeDrawValidator (gl, 821 (m_separatePrograms) ? (programPipeline->getPipeline()) : (vertexProgramID), 822 (m_separatePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE) : (BeforeDrawValidator::TARGETTYPE_PROGRAM)); 823 824 vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0])); 825 826 // Collect VA pointer for inputs 827 for (int valNdx = 0; valNdx < numValues; valNdx++) 828 { 829 const ShaderCase::Value& val = valueBlock.values[valNdx]; 830 const char* const valueName = val.valueName.c_str(); 831 const DataType dataType = val.dataType; 832 const int scalarSize = getDataTypeScalarSize(val.dataType); 833 834 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 835 { 836 // Replicate values four times. 837 std::vector<float>& scalars = attribValues[attribValueNdx++]; 838 scalars.resize(numVerticesPerDraw * scalarSize); 839 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType)) 840 { 841 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 842 for (int ndx = 0; ndx < scalarSize; ndx++) 843 scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32; 844 } 845 else 846 { 847 // convert to floats. 848 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 849 { 850 for (int ndx = 0; ndx < scalarSize; ndx++) 851 { 852 float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32; 853 DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v); 854 scalars[repNdx*scalarSize + ndx] = v; 855 } 856 } 857 } 858 859 // Attribute name prefix. 860 string attribPrefix = ""; 861 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)? 862 if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT)) 863 attribPrefix = "a_"; 864 865 // Input always given as attribute. 866 string attribName = attribPrefix + valueName; 867 int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str()); 868 if (attribLoc == -1) 869 { 870 log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage; 871 continue; 872 } 873 874 if (isDataTypeMatrix(dataType)) 875 { 876 int numCols = getDataTypeMatrixNumColumns(dataType); 877 int numRows = getDataTypeMatrixNumRows(dataType); 878 DE_ASSERT(scalarSize == numCols*numRows); 879 880 for (int i = 0; i < numCols; i++) 881 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*sizeof(float), &scalars[i * numRows])); 882 } 883 else 884 { 885 DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType)); 886 vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0])); 887 } 888 889 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array"); 890 } 891 } 892 893 GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms"); 894 895 // set uniform values for outputs (refs). 896 for (int valNdx = 0; valNdx < numValues; valNdx++) 897 { 898 const ShaderCase::Value& val = valueBlock.values[valNdx]; 899 const char* const valueName = val.valueName.c_str(); 900 901 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 902 { 903 // Set reference value. 904 string refName = string("ref_") + valueName; 905 setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog()); 906 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms"); 907 } 908 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM) 909 { 910 setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog()); 911 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms"); 912 } 913 } 914 915 // Clear. 916 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f); 917 gl.clear(GL_COLOR_BUFFER_BIT); 918 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer"); 919 920 // Use program or pipeline 921 if (m_separatePrograms) 922 gl.useProgram(0); 923 else 924 gl.useProgram(vertexProgramID); 925 926 // Draw. 927 if (tessellationPresent) 928 { 929 gl.patchParameteri(GL_PATCH_VERTICES, 3); 930 GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)"); 931 } 932 933 draw(m_renderCtx, 934 vertexProgramID, 935 (int)vertexArrays.size(), 936 &vertexArrays[0], 937 (tessellationPresent) ? 938 (pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) : 939 (pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])), 940 (m_expectResult == EXPECT_VALIDATION_FAIL) ? 941 (&beforeDrawValidator) : 942 (DE_NULL)); 943 944 postDrawError = gl.getError(); 945 946 if (m_expectResult == EXPECT_PASS) 947 { 948 // Read back results. 949 Surface surface (width, height); 950 const float w = s_positions[3]; 951 const int minY = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * height + 1.0f); 952 const int maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * height - 0.5f); 953 const int minX = deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * width + 1.0f); 954 const int maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * width - 0.5f); 955 956 GLU_EXPECT_NO_ERROR(postDrawError, "draw"); 957 958 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess()); 959 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 960 961 if (!checkPixels(surface, minX, maxX, minY, maxY)) 962 { 963 log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx+1) << " of " << (int)m_valueBlocks.size() 964 << ", sub-case " << arrayNdx+1 << " of " << valueBlock.arrayLength << "):" 965 << TestLog::EndMessage; 966 967 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage; 968 dumpValues(valueBlock, arrayNdx); 969 970 // Dump image on failure. 971 log << TestLog::Image("Result", "Rendered result image", surface); 972 973 gl.useProgram(0); 974 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 975 return false; 976 } 977 } 978 else if (m_expectResult == EXPECT_VALIDATION_FAIL) 979 { 980 log << TestLog::Message 981 << "Draw call generated error: " 982 << glu::getErrorStr(postDrawError) << " " 983 << ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n" 984 << "Validate status: " 985 << glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " " 986 << ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n" 987 << "Info log: " 988 << ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n" 989 << TestLog::EndMessage; 990 991 // test result 992 993 if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION) 994 { 995 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str()); 996 return false; 997 } 998 999 if (beforeDrawValidator.getValidateStatus() == GL_TRUE) 1000 { 1001 if (postDrawError == GL_NO_ERROR) 1002 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded"); 1003 else if (postDrawError == GL_INVALID_OPERATION) 1004 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)"); 1005 else 1006 DE_ASSERT(false); 1007 return false; 1008 } 1009 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR) 1010 { 1011 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)"); 1012 return false; 1013 } 1014 else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION) 1015 { 1016 // Validation does not depend on input values, no need to test all values 1017 return true; 1018 } 1019 else 1020 DE_ASSERT(false); 1021 } 1022 else 1023 DE_ASSERT(false); 1024 } 1025 } 1026 1027 gl.useProgram(0); 1028 if (m_separatePrograms) 1029 gl.bindProgramPipeline(0); 1030 1031 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end"); 1032 return true; 1033 } 1034 1035 TestCase::IterateResult ShaderCase::iterate (void) 1036 { 1037 // Initialize state to pass. 1038 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1039 1040 bool executeOk = execute(); 1041 1042 DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); 1043 DE_UNREF(executeOk); 1044 return TestCase::STOP; 1045 } 1046 1047 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<ShaderCase::CaseRequirement>& requirements, glu::ShaderType type) 1048 { 1049 for (int ndx = 0; ndx < (int)requirements.size(); ++ndx) 1050 if (requirements[ndx].getType() == ShaderCase::CaseRequirement::REQUIREMENTTYPE_EXTENSION && 1051 (requirements[ndx].getAffectedExtensionStageFlags() & (1 << (deUint32)type)) != 0) 1052 buf << "#extension " << requirements[ndx].getSupportedExtension() << " : require\n"; 1053 } 1054 1055 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations 1056 static std::string injectExtensionRequirements (const std::string& baseCode, glu::ShaderType shaderType, const std::vector<ShaderCase::CaseRequirement>& requirements) 1057 { 1058 std::istringstream baseCodeBuf(baseCode); 1059 std::ostringstream resultBuf; 1060 std::string line; 1061 bool firstNonPreprocessorLine = true; 1062 std::ostringstream extensions; 1063 1064 generateExtensionStatements(extensions, requirements, shaderType); 1065 1066 // skip if no requirements 1067 if (extensions.str().empty()) 1068 return baseCode; 1069 1070 while (std::getline(baseCodeBuf, line)) 1071 { 1072 // begins with '#'? 1073 const std::string::size_type firstNonWhitespace = line.find_first_not_of("\t "); 1074 const bool isPreprocessorDirective = (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#'); 1075 1076 // Inject #extensions 1077 if (!isPreprocessorDirective && firstNonPreprocessorLine) 1078 { 1079 firstNonPreprocessorLine = false; 1080 resultBuf << extensions.str(); 1081 } 1082 1083 resultBuf << line << "\n"; 1084 } 1085 1086 return resultBuf.str(); 1087 } 1088 1089 // This functions builds a matching vertex shader for a 'both' case, when 1090 // the fragment shader is being tested. 1091 // We need to build attributes and varyings for each 'input'. 1092 string ShaderCase::genVertexShader (const ValueBlock& valueBlock) const 1093 { 1094 ostringstream res; 1095 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 1096 const char* vtxIn = usesInout ? "in" : "attribute"; 1097 const char* vtxOut = usesInout ? "out" : "varying"; 1098 1099 res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n"; 1100 1101 // Declarations (position + attribute/varying for each input). 1102 res << "precision highp float;\n"; 1103 res << "precision highp int;\n"; 1104 res << "\n"; 1105 res << vtxIn << " highp vec4 dEQP_Position;\n"; 1106 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1107 { 1108 const ShaderCase::Value& val = valueBlock.values[ndx]; 1109 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 1110 { 1111 DataType floatType = getDataTypeFloatScalars(val.dataType); 1112 const char* typeStr = getDataTypeName(floatType); 1113 res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n"; 1114 1115 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1116 res << vtxOut << " " << typeStr << " " << val.valueName << ";\n"; 1117 else 1118 res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n"; 1119 } 1120 } 1121 res << "\n"; 1122 1123 // Main function. 1124 // - gl_Position = dEQP_Position; 1125 // - for each input: write attribute directly to varying 1126 res << "void main()\n"; 1127 res << "{\n"; 1128 res << " gl_Position = dEQP_Position;\n"; 1129 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1130 { 1131 const ShaderCase::Value& val = valueBlock.values[ndx]; 1132 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 1133 { 1134 const string& name = val.valueName; 1135 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1136 res << " " << name << " = a_" << name << ";\n"; 1137 else 1138 res << " v_" << name << " = a_" << name << ";\n"; 1139 } 1140 } 1141 1142 res << "}\n"; 1143 return res.str(); 1144 } 1145 1146 static void genCompareFunctions (ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes) 1147 { 1148 bool cmpTypeFound[TYPE_LAST]; 1149 for (int i = 0; i < TYPE_LAST; i++) 1150 cmpTypeFound[i] = false; 1151 1152 for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++) 1153 { 1154 const ShaderCase::Value& val = valueBlock.values[valueNdx]; 1155 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1156 cmpTypeFound[(int)val.dataType] = true; 1157 } 1158 1159 if (useFloatTypes) 1160 { 1161 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n"; 1162 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n"; 1163 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n"; 1164 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n"; 1165 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n"; 1166 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n"; 1167 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n"; 1168 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n"; 1169 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n"; 1170 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n"; 1171 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n"; 1172 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n"; 1173 } 1174 else 1175 { 1176 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (bool a, bool b) { return (a == b); }\n"; 1177 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n"; 1178 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n"; 1179 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n"; 1180 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (int a, int b) { return (a == b); }\n"; 1181 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n"; 1182 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n"; 1183 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n"; 1184 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (uint a, uint b) { return (a == b); }\n"; 1185 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n"; 1186 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n"; 1187 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n"; 1188 } 1189 1190 if (cmpTypeFound[TYPE_FLOAT]) stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n"; 1191 if (cmpTypeFound[TYPE_FLOAT_VEC2]) stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1192 if (cmpTypeFound[TYPE_FLOAT_VEC3]) stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1193 if (cmpTypeFound[TYPE_FLOAT_VEC4]) stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1194 1195 if (cmpTypeFound[TYPE_FLOAT_MAT2]) stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1196 if (cmpTypeFound[TYPE_FLOAT_MAT2X3]) stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1197 if (cmpTypeFound[TYPE_FLOAT_MAT2X4]) stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1198 if (cmpTypeFound[TYPE_FLOAT_MAT3X2]) stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1199 if (cmpTypeFound[TYPE_FLOAT_MAT3]) stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1200 if (cmpTypeFound[TYPE_FLOAT_MAT3X4]) stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1201 if (cmpTypeFound[TYPE_FLOAT_MAT4X2]) stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1202 if (cmpTypeFound[TYPE_FLOAT_MAT4X3]) stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1203 if (cmpTypeFound[TYPE_FLOAT_MAT4]) stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1204 } 1205 1206 static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName) 1207 { 1208 bool isFirstOutput = true; 1209 1210 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1211 { 1212 const ShaderCase::Value& val = valueBlock.values[ndx]; 1213 const char* valueName = val.valueName.c_str(); 1214 1215 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1216 { 1217 // Check if we're only interested in one variable (then skip if not the right one). 1218 if (checkVarName && !deStringEqual(valueName, checkVarName)) 1219 continue; 1220 1221 // Prefix. 1222 if (isFirstOutput) 1223 { 1224 output << "bool RES = "; 1225 isFirstOutput = false; 1226 } 1227 else 1228 output << "RES = RES && "; 1229 1230 // Generate actual comparison. 1231 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1232 output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n"; 1233 else 1234 output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n"; 1235 } 1236 // \note Uniforms are already declared in shader. 1237 } 1238 1239 if (isFirstOutput) 1240 output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case? 1241 else 1242 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n"; 1243 } 1244 1245 string ShaderCase::genFragmentShader (const ValueBlock& valueBlock) const 1246 { 1247 ostringstream shader; 1248 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 1249 const bool customColorOut = usesInout; 1250 const char* fragIn = usesInout ? "in" : "varying"; 1251 const char* prec = supportsFragmentHighp(m_targetVersion) ? "highp" : "mediump"; 1252 1253 shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n"; 1254 1255 shader << "precision " << prec << " float;\n"; 1256 shader << "precision " << prec << " int;\n"; 1257 shader << "\n"; 1258 1259 if (customColorOut) 1260 { 1261 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1262 shader << "\n"; 1263 } 1264 1265 genCompareFunctions(shader, valueBlock, true); 1266 shader << "\n"; 1267 1268 // Declarations (varying, reference for each output). 1269 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1270 { 1271 const ShaderCase::Value& val = valueBlock.values[ndx]; 1272 DataType floatType = getDataTypeFloatScalars(val.dataType); 1273 const char* floatTypeStr = getDataTypeName(floatType); 1274 const char* refTypeStr = getDataTypeName(val.dataType); 1275 1276 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1277 { 1278 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1279 shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n"; 1280 else 1281 shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n"; 1282 1283 shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n"; 1284 } 1285 } 1286 1287 shader << "\n"; 1288 shader << "void main()\n"; 1289 shader << "{\n"; 1290 1291 shader << " "; 1292 genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL); 1293 1294 shader << "}\n"; 1295 return shader.str(); 1296 } 1297 1298 // Specialize a shader for the vertex shader test case. 1299 string ShaderCase::specializeVertexShader (const char* src, const ValueBlock& valueBlock) const 1300 { 1301 ostringstream decl; 1302 ostringstream setup; 1303 ostringstream output; 1304 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 1305 const char* vtxIn = usesInout ? "in" : "attribute"; 1306 const char* vtxOut = usesInout ? "out" : "varying"; 1307 1308 // generated from "both" case 1309 DE_ASSERT(m_caseType == CASETYPE_VERTEX_ONLY); 1310 1311 // Output (write out position). 1312 output << "gl_Position = dEQP_Position;\n"; 1313 1314 // Declarations (position + attribute for each input, varying for each output). 1315 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 1316 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1317 { 1318 const ShaderCase::Value& val = valueBlock.values[ndx]; 1319 const char* valueName = val.valueName.c_str(); 1320 DataType floatType = getDataTypeFloatScalars(val.dataType); 1321 const char* floatTypeStr = getDataTypeName(floatType); 1322 const char* refTypeStr = getDataTypeName(val.dataType); 1323 1324 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 1325 { 1326 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1327 { 1328 decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n"; 1329 } 1330 else 1331 { 1332 decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n"; 1333 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n"; 1334 } 1335 } 1336 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1337 { 1338 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1339 decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n"; 1340 else 1341 { 1342 decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n"; 1343 decl << refTypeStr << " " << valueName << ";\n"; 1344 1345 output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n"; 1346 } 1347 } 1348 } 1349 1350 // Shader specialization. 1351 map<string, string> params; 1352 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 1353 params.insert(pair<string, string>("SETUP", setup.str())); 1354 params.insert(pair<string, string>("OUTPUT", output.str())); 1355 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position")); 1356 1357 StringTemplate tmpl (src); 1358 const string baseSrc = tmpl.specialize(params); 1359 const string withExt = injectExtensionRequirements(baseSrc, SHADERTYPE_VERTEX, m_programs[0].spec.requirements); 1360 1361 return withExt; 1362 } 1363 1364 // Specialize a shader for the fragment shader test case. 1365 string ShaderCase::specializeFragmentShader (const char* src, const ValueBlock& valueBlock) const 1366 { 1367 ostringstream decl; 1368 ostringstream setup; 1369 ostringstream output; 1370 1371 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 1372 const bool customColorOut = usesInout; 1373 const char* fragIn = usesInout ? "in" : "varying"; 1374 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 1375 1376 // generated from "both" case 1377 DE_ASSERT(m_caseType == CASETYPE_FRAGMENT_ONLY); 1378 1379 genCompareFunctions(decl, valueBlock, false); 1380 genCompareOp(output, fragColor, valueBlock, "", DE_NULL); 1381 1382 if (customColorOut) 1383 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1384 1385 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1386 { 1387 const ShaderCase::Value& val = valueBlock.values[ndx]; 1388 const char* valueName = val.valueName.c_str(); 1389 DataType floatType = getDataTypeFloatScalars(val.dataType); 1390 const char* floatTypeStr = getDataTypeName(floatType); 1391 const char* refTypeStr = getDataTypeName(val.dataType); 1392 1393 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 1394 { 1395 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1396 decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n"; 1397 else 1398 { 1399 decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n"; 1400 std::string offset = isDataTypeIntOrIVec(val.dataType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation 1401 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset << ");\n"; 1402 } 1403 } 1404 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1405 { 1406 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n"; 1407 decl << refTypeStr << " " << valueName << ";\n"; 1408 } 1409 } 1410 1411 /* \todo [2010-04-01 petri] Check all outputs. */ 1412 1413 // Shader specialization. 1414 map<string, string> params; 1415 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 1416 params.insert(pair<string, string>("SETUP", setup.str())); 1417 params.insert(pair<string, string>("OUTPUT", output.str())); 1418 params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor)); 1419 1420 StringTemplate tmpl (src); 1421 const string baseSrc = tmpl.specialize(params); 1422 const string withExt = injectExtensionRequirements(baseSrc, SHADERTYPE_FRAGMENT, m_programs[0].spec.requirements); 1423 1424 return withExt; 1425 } 1426 1427 static map<string, string> generateVertexSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock) 1428 { 1429 const bool usesInout = usesShaderInoutQualifiers(targetVersion); 1430 const char* vtxIn = usesInout ? "in" : "attribute"; 1431 ostringstream decl; 1432 ostringstream setup; 1433 map<string, string> params; 1434 1435 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 1436 1437 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1438 { 1439 const ShaderCase::Value& val = valueBlock.values[ndx]; 1440 const char* typeStr = getDataTypeName(val.dataType); 1441 1442 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 1443 { 1444 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 1445 { 1446 decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n"; 1447 } 1448 else 1449 { 1450 DataType floatType = getDataTypeFloatScalars(val.dataType); 1451 const char* floatTypeStr = getDataTypeName(floatType); 1452 1453 decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n"; 1454 setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n"; 1455 } 1456 } 1457 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && 1458 val.valueName.find('.') == string::npos) 1459 decl << "uniform " << typeStr << " " << val.valueName << ";\n"; 1460 } 1461 1462 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str())); 1463 params.insert(pair<string, string>("VERTEX_SETUP", setup.str())); 1464 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n"))); 1465 return params; 1466 } 1467 1468 static map<string, string> generateFragmentSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock) 1469 { 1470 const bool usesInout = usesShaderInoutQualifiers(targetVersion); 1471 const bool customColorOut = usesInout; 1472 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 1473 ostringstream decl; 1474 ostringstream output; 1475 map<string, string> params; 1476 1477 genCompareFunctions(decl, valueBlock, false); 1478 genCompareOp(output, fragColor, valueBlock, "", DE_NULL); 1479 1480 if (customColorOut) 1481 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1482 1483 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1484 { 1485 const ShaderCase::Value& val = valueBlock.values[ndx]; 1486 const char* valueName = val.valueName.c_str(); 1487 const char* refTypeStr = getDataTypeName(val.dataType); 1488 1489 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 1490 { 1491 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n"; 1492 decl << refTypeStr << " " << valueName << ";\n"; 1493 } 1494 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && 1495 val.valueName.find('.') == string::npos) 1496 { 1497 decl << "uniform " << refTypeStr << " " << valueName << ";\n"; 1498 } 1499 } 1500 1501 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str())); 1502 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str())); 1503 params.insert(pair<string, string>("FRAG_COLOR", fragColor)); 1504 return params; 1505 } 1506 1507 static map<string, string> generateGeometrySpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock) 1508 { 1509 ostringstream decl; 1510 map<string, string> params; 1511 1512 DE_UNREF(targetVersion); 1513 1514 decl << "layout (triangles) in;\n"; 1515 decl << "layout (triangle_strip, max_vertices=3) out;\n"; 1516 decl << "\n"; 1517 1518 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1519 { 1520 const ShaderCase::Value& val = valueBlock.values[ndx]; 1521 const char* valueName = val.valueName.c_str(); 1522 const char* refTypeStr = getDataTypeName(val.dataType); 1523 1524 if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && 1525 val.valueName.find('.') == string::npos) 1526 { 1527 decl << "uniform " << refTypeStr << " " << valueName << ";\n"; 1528 } 1529 } 1530 1531 params.insert(pair<string, string>("GEOMETRY_DECLARATIONS", decl.str())); 1532 return params; 1533 } 1534 1535 static map<string, string> generateTessControlSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock) 1536 { 1537 ostringstream decl; 1538 ostringstream output; 1539 map<string, string> params; 1540 1541 DE_UNREF(targetVersion); 1542 1543 decl << "layout (vertices=3) out;\n"; 1544 decl << "\n"; 1545 1546 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1547 { 1548 const ShaderCase::Value& val = valueBlock.values[ndx]; 1549 const char* valueName = val.valueName.c_str(); 1550 const char* refTypeStr = getDataTypeName(val.dataType); 1551 1552 if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && 1553 val.valueName.find('.') == string::npos) 1554 { 1555 decl << "uniform " << refTypeStr << " " << valueName << ";\n"; 1556 } 1557 } 1558 1559 output << "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 1560 "gl_TessLevelInner[0] = 2.0;\n" 1561 "gl_TessLevelInner[1] = 2.0;\n" 1562 "gl_TessLevelOuter[0] = 2.0;\n" 1563 "gl_TessLevelOuter[1] = 2.0;\n" 1564 "gl_TessLevelOuter[2] = 2.0;\n" 1565 "gl_TessLevelOuter[3] = 2.0;"; 1566 1567 params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS", decl.str())); 1568 params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT", output.str())); 1569 return params; 1570 } 1571 1572 static map<string, string> generateTessEvalSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock) 1573 { 1574 ostringstream decl; 1575 ostringstream output; 1576 map<string, string> params; 1577 1578 DE_UNREF(targetVersion); 1579 1580 decl << "layout (triangles) in;\n"; 1581 decl << "\n"; 1582 1583 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 1584 { 1585 const ShaderCase::Value& val = valueBlock.values[ndx]; 1586 const char* valueName = val.valueName.c_str(); 1587 const char* refTypeStr = getDataTypeName(val.dataType); 1588 1589 if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && 1590 val.valueName.find('.') == string::npos) 1591 { 1592 decl << "uniform " << refTypeStr << " " << valueName << ";\n"; 1593 } 1594 } 1595 1596 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"; 1597 1598 params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS", decl.str())); 1599 params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT", output.str())); 1600 return params; 1601 } 1602 1603 static void specializeShaders (glu::ProgramSources& dst, glu::ShaderType shaderType, const std::vector<std::string>& sources, const ShaderCase::ValueBlock& valueBlock, glu::GLSLVersion targetVersion, const std::vector<ShaderCase::CaseRequirement>& requirements, std::map<std::string, std::string> (*specializationGenerator)(glu::GLSLVersion, const ShaderCase::ValueBlock&)) 1604 { 1605 if (!sources.empty()) 1606 { 1607 const std::map<std::string, std::string> specializationParams = specializationGenerator(targetVersion, valueBlock); 1608 1609 for (int ndx = 0; ndx < (int)sources.size(); ++ndx) 1610 { 1611 const StringTemplate tmpl (sources[ndx]); 1612 const std::string baseGLSLCode = tmpl.specialize(specializationParams); 1613 const std::string glslSource = injectExtensionRequirements(baseGLSLCode, shaderType, requirements); 1614 1615 dst << glu::ShaderSource(shaderType, glslSource); 1616 } 1617 } 1618 } 1619 1620 void ShaderCase::specializeVertexShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const 1621 { 1622 specializeShaders(dst, glu::SHADERTYPE_VERTEX, sources, valueBlock, m_targetVersion, requirements, generateVertexSpecialization); 1623 } 1624 1625 void ShaderCase::specializeFragmentShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const 1626 { 1627 specializeShaders(dst, glu::SHADERTYPE_FRAGMENT, sources, valueBlock, m_targetVersion, requirements, generateFragmentSpecialization); 1628 } 1629 1630 void ShaderCase::specializeGeometryShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const 1631 { 1632 specializeShaders(dst, glu::SHADERTYPE_GEOMETRY, sources, valueBlock, m_targetVersion, requirements, generateGeometrySpecialization); 1633 } 1634 1635 void ShaderCase::specializeTessControlShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const 1636 { 1637 specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_CONTROL, sources, valueBlock, m_targetVersion, requirements, generateTessControlSpecialization); 1638 } 1639 1640 void ShaderCase::specializeTessEvalShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const 1641 { 1642 specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_EVALUATION, sources, valueBlock, m_targetVersion, requirements, generateTessEvalSpecialization); 1643 } 1644 1645 void ShaderCase::dumpValues (const ValueBlock& valueBlock, int arrayNdx) 1646 { 1647 int numValues = (int)valueBlock.values.size(); 1648 for (int valNdx = 0; valNdx < numValues; valNdx++) 1649 { 1650 const ShaderCase::Value& val = valueBlock.values[valNdx]; 1651 const char* valueName = val.valueName.c_str(); 1652 DataType dataType = val.dataType; 1653 int scalarSize = getDataTypeScalarSize(val.dataType); 1654 ostringstream result; 1655 1656 result << " "; 1657 if (val.storageType == Value::STORAGE_INPUT) 1658 result << "input "; 1659 else if (val.storageType == Value::STORAGE_UNIFORM) 1660 result << "uniform "; 1661 else if (val.storageType == Value::STORAGE_OUTPUT) 1662 result << "expected "; 1663 1664 result << getDataTypeName(dataType) << " " << valueName << ":"; 1665 1666 if (isDataTypeScalar(dataType)) 1667 result << " "; 1668 if (isDataTypeVector(dataType)) 1669 result << " [ "; 1670 else if (isDataTypeMatrix(dataType)) 1671 result << "\n"; 1672 1673 if (isDataTypeScalarOrVector(dataType)) 1674 { 1675 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1676 { 1677 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx; 1678 const Value::Element& e = val.elements[elemNdx*scalarSize + scalarNdx]; 1679 result << ((scalarNdx != 0) ? ", " : ""); 1680 1681 if (isDataTypeFloatOrVec(dataType)) 1682 result << e.float32; 1683 else if (isDataTypeIntOrIVec(dataType)) 1684 result << e.int32; 1685 else if (isDataTypeUintOrUVec(dataType)) 1686 result << (deUint32)e.int32; 1687 else if (isDataTypeBoolOrBVec(dataType)) 1688 result << (e.bool32 ? "true" : "false"); 1689 } 1690 } 1691 else if (isDataTypeMatrix(dataType)) 1692 { 1693 int numRows = getDataTypeMatrixNumRows(dataType); 1694 int numCols = getDataTypeMatrixNumColumns(dataType); 1695 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1696 { 1697 result << " [ "; 1698 for (int colNdx = 0; colNdx < numCols; colNdx++) 1699 { 1700 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx; 1701 float v = val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32; 1702 result << ((colNdx==0) ? "" : ", ") << v; 1703 } 1704 result << " ]\n"; 1705 } 1706 } 1707 1708 if (isDataTypeScalar(dataType)) 1709 result << "\n"; 1710 else if (isDataTypeVector(dataType)) 1711 result << " ]\n"; 1712 1713 m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage; 1714 } 1715 } 1716 1717 } // sl 1718 } // gls 1719 } // deqp 1720