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