1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 Google Inc. 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief Compiler test case. 23 */ /*-------------------------------------------------------------------*/ 24 25 #include "glcShaderLibraryCase.hpp" 26 27 #include "tcuRenderTarget.hpp" 28 #include "tcuTestLog.hpp" 29 30 #include "gluDrawUtil.hpp" 31 #include "gluPixelTransfer.hpp" 32 #include "gluShaderProgram.hpp" 33 #include "tcuStringTemplate.hpp" 34 35 #include "glwEnums.hpp" 36 #include "glwFunctions.hpp" 37 38 #include "deInt32.h" 39 #include "deMath.h" 40 #include "deRandom.hpp" 41 #include "deString.h" 42 43 #include <map> 44 #include <sstream> 45 #include <string> 46 #include <vector> 47 48 using namespace std; 49 using namespace tcu; 50 using namespace glu; 51 52 namespace deqp 53 { 54 namespace sl 55 { 56 57 enum 58 { 59 VIEWPORT_WIDTH = 128, 60 VIEWPORT_HEIGHT = 128 61 }; 62 63 static inline bool usesShaderInoutQualifiers(glu::GLSLVersion version) 64 { 65 switch (version) 66 { 67 case glu::GLSL_VERSION_100_ES: 68 case glu::GLSL_VERSION_130: 69 case glu::GLSL_VERSION_140: 70 case glu::GLSL_VERSION_150: 71 return false; 72 73 default: 74 return true; 75 } 76 } 77 78 // ShaderCase. 79 80 ShaderCase::ShaderCase(tcu::TestContext& testCtx, RenderContext& renderCtx, const char* name, const char* description, 81 ExpectResult expectResult, const std::vector<ValueBlock>& valueBlocks, GLSLVersion targetVersion, 82 const char* vertexSource, const char* fragmentSource) 83 : tcu::TestCase(testCtx, name, description) 84 , m_renderCtx(renderCtx) 85 , m_expectResult(expectResult) 86 , m_valueBlocks(valueBlocks) 87 , m_targetVersion(targetVersion) 88 { 89 // If no value blocks given, use an empty one. 90 if (m_valueBlocks.size() == 0) 91 m_valueBlocks.push_back(ValueBlock()); 92 93 // Use first value block to specialize shaders. 94 const ValueBlock& valueBlock = m_valueBlocks[0]; 95 96 // \todo [2010-04-01 petri] Check that all value blocks have matching values. 97 98 // Generate specialized shader sources. 99 if (vertexSource && fragmentSource) 100 { 101 m_caseType = CASETYPE_COMPLETE; 102 specializeShaders(vertexSource, fragmentSource, m_vertexSource, m_fragmentSource, valueBlock); 103 } 104 else if (vertexSource) 105 { 106 m_caseType = CASETYPE_VERTEX_ONLY; 107 m_vertexSource = specializeVertexShader(vertexSource, valueBlock); 108 m_fragmentSource = genFragmentShader(valueBlock); 109 } 110 else 111 { 112 DE_ASSERT(fragmentSource); 113 m_caseType = CASETYPE_FRAGMENT_ONLY; 114 m_vertexSource = genVertexShader(valueBlock); 115 m_fragmentSource = specializeFragmentShader(fragmentSource, valueBlock); 116 } 117 } 118 119 ShaderCase::~ShaderCase(void) 120 { 121 } 122 123 static void setUniformValue(const glw::Functions& gl, deUint32 programID, const std::string& name, 124 const ShaderCase::Value& val, int arrayNdx) 125 { 126 int scalarSize = getDataTypeScalarSize(val.dataType); 127 int loc = gl.getUniformLocation(programID, name.c_str()); 128 129 TCU_CHECK_MSG(loc != -1, "uniform location not found"); 130 131 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat)); 132 DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint)); 133 134 int elemNdx = (val.arrayLength == 1) ? 0 : (arrayNdx * scalarSize); 135 136 switch (val.dataType) 137 { 138 case TYPE_FLOAT: 139 gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32); 140 break; 141 case TYPE_FLOAT_VEC2: 142 gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32); 143 break; 144 case TYPE_FLOAT_VEC3: 145 gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32); 146 break; 147 case TYPE_FLOAT_VEC4: 148 gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32); 149 break; 150 case TYPE_FLOAT_MAT2: 151 gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 152 break; 153 case TYPE_FLOAT_MAT3: 154 gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 155 break; 156 case TYPE_FLOAT_MAT4: 157 gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 158 break; 159 case TYPE_INT: 160 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); 161 break; 162 case TYPE_INT_VEC2: 163 gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); 164 break; 165 case TYPE_INT_VEC3: 166 gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); 167 break; 168 case TYPE_INT_VEC4: 169 gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); 170 break; 171 case TYPE_BOOL: 172 gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32); 173 break; 174 case TYPE_BOOL_VEC2: 175 gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32); 176 break; 177 case TYPE_BOOL_VEC3: 178 gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32); 179 break; 180 case TYPE_BOOL_VEC4: 181 gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32); 182 break; 183 case TYPE_UINT: 184 gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); 185 break; 186 case TYPE_UINT_VEC2: 187 gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); 188 break; 189 case TYPE_UINT_VEC3: 190 gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); 191 break; 192 case TYPE_UINT_VEC4: 193 gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32); 194 break; 195 case TYPE_FLOAT_MAT2X3: 196 gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 197 break; 198 case TYPE_FLOAT_MAT2X4: 199 gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 200 break; 201 case TYPE_FLOAT_MAT3X2: 202 gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 203 break; 204 case TYPE_FLOAT_MAT3X4: 205 gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 206 break; 207 case TYPE_FLOAT_MAT4X2: 208 gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 209 break; 210 case TYPE_FLOAT_MAT4X3: 211 gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32); 212 break; 213 214 case TYPE_SAMPLER_2D: 215 case TYPE_SAMPLER_CUBE: 216 DE_ASSERT(DE_FALSE && "implement!"); 217 break; 218 219 default: 220 DE_ASSERT(false); 221 } 222 } 223 224 bool ShaderCase::checkPixels(Surface& surface, int minX, int maxX, int minY, int maxY) 225 { 226 TestLog& log = m_testCtx.getLog(); 227 bool allWhite = true; 228 bool allBlack = true; 229 bool anyUnexpected = false; 230 231 DE_ASSERT((maxX > minX) && (maxY > minY)); 232 233 for (int y = minY; y <= maxY; y++) 234 { 235 for (int x = minX; x <= maxX; x++) 236 { 237 RGBA pixel = surface.getPixel(x, y); 238 // Note: we really do not want to involve alpha in the check comparison 239 // \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black. 240 bool isWhite = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255); 241 bool isBlack = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0); 242 243 allWhite = allWhite && isWhite; 244 allBlack = allBlack && isBlack; 245 anyUnexpected = anyUnexpected || (!isWhite && !isBlack); 246 } 247 } 248 249 if (!allWhite) 250 { 251 if (anyUnexpected) 252 log << TestLog::Message 253 << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" 254 << TestLog::EndMessage; 255 else if (!allBlack) 256 log << TestLog::Message 257 << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" 258 << TestLog::EndMessage; 259 260 return false; 261 } 262 return true; 263 } 264 265 bool ShaderCase::execute(void) 266 { 267 TestLog& log = m_testCtx.getLog(); 268 const glw::Functions& gl = m_renderCtx.getFunctions(); 269 270 // Compute viewport. 271 const tcu::RenderTarget& renderTarget = m_renderCtx.getRenderTarget(); 272 de::Random rnd(deStringHash(getName())); 273 int width = deMin32(renderTarget.getWidth(), VIEWPORT_WIDTH); 274 int height = deMin32(renderTarget.getHeight(), VIEWPORT_HEIGHT); 275 int viewportX = rnd.getInt(0, renderTarget.getWidth() - width); 276 int viewportY = rnd.getInt(0, renderTarget.getHeight() - height); 277 const int numVerticesPerDraw = 4; 278 279 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start"); 280 281 // Setup viewport. 282 gl.viewport(viewportX, viewportY, width, height); 283 284 const float quadSize = 1.0f; 285 static const float s_positions[4 * 4] = { -quadSize, -quadSize, 0.0f, 1.0f, -quadSize, +quadSize, 0.0f, 1.0f, 286 +quadSize, -quadSize, 0.0f, 1.0f, +quadSize, +quadSize, 0.0f, 1.0f }; 287 288 static const deUint16 s_indices[2 * 3] = { 0, 1, 2, 1, 3, 2 }; 289 290 // Setup program. 291 glu::ShaderProgram program(m_renderCtx, glu::makeVtxFragSources(m_vertexSource.c_str(), m_fragmentSource.c_str())); 292 293 // Check that compile/link results are what we expect. 294 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk; 295 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk; 296 bool linkOk = program.getProgramInfo().linkOk; 297 const char* failReason = DE_NULL; 298 299 log << program; 300 301 switch (m_expectResult) 302 { 303 case EXPECT_PASS: 304 if (!vertexOk || !fragmentOk) 305 failReason = "expected shaders to compile and link properly, but failed to compile."; 306 else if (!linkOk) 307 failReason = "expected shaders to compile and link properly, but failed to link."; 308 break; 309 310 case EXPECT_COMPILE_FAIL: 311 if (vertexOk && fragmentOk && !linkOk) 312 failReason = "expected compilation to fail, but both shaders compiled and link failed."; 313 else if (vertexOk && fragmentOk) 314 failReason = "expected compilation to fail, but both shaders compiled correctly."; 315 break; 316 317 case EXPECT_LINK_FAIL: 318 if (!vertexOk || !fragmentOk) 319 failReason = "expected linking to fail, but unable to compile."; 320 else if (linkOk) 321 failReason = "expected linking to fail, but passed."; 322 break; 323 324 default: 325 DE_ASSERT(false); 326 return false; 327 } 328 329 if (failReason != DE_NULL) 330 { 331 // \todo [2010-06-07 petri] These should be handled in the test case? 332 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage; 333 334 // If implementation parses shader at link time, report it as quality warning. 335 if (m_expectResult == EXPECT_COMPILE_FAIL && vertexOk && fragmentOk && !linkOk) 336 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason); 337 else 338 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason); 339 return false; 340 } 341 342 // Return if compile/link expected to fail. 343 if (m_expectResult != EXPECT_PASS) 344 return (failReason == DE_NULL); 345 346 // Start using program. 347 deUint32 programID = program.getProgram(); 348 gl.useProgram(programID); 349 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()"); 350 351 // Fetch location for positions positions. 352 int positionLoc = gl.getAttribLocation(programID, "dEQP_Position"); 353 if (positionLoc == -1) 354 { 355 string errStr = string("no location found for attribute 'dEQP_Position'"); 356 TCU_FAIL(errStr.c_str()); 357 } 358 359 // Iterate all value blocks. 360 for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++) 361 { 362 const ValueBlock& valueBlock = m_valueBlocks[blockNdx]; 363 364 // Iterate all array sub-cases. 365 for (int arrayNdx = 0; arrayNdx < valueBlock.arrayLength; arrayNdx++) 366 { 367 int numValues = (int)valueBlock.values.size(); 368 vector<VertexArrayBinding> vertexArrays; 369 370 int attribValueNdx = 0; 371 vector<vector<float> > attribValues(numValues); 372 373 vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0])); 374 375 // Collect VA pointer for inputs and set uniform values for outputs (refs). 376 for (int valNdx = 0; valNdx < numValues; valNdx++) 377 { 378 const ShaderCase::Value& val = valueBlock.values[valNdx]; 379 const char* valueName = val.valueName.c_str(); 380 DataType dataType = val.dataType; 381 int scalarSize = getDataTypeScalarSize(val.dataType); 382 383 GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms"); 384 385 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 386 { 387 // Replicate values four times. 388 std::vector<float>& scalars = attribValues[attribValueNdx++]; 389 scalars.resize(numVerticesPerDraw * scalarSize); 390 if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType)) 391 { 392 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 393 for (int ndx = 0; ndx < scalarSize; ndx++) 394 scalars[repNdx * scalarSize + ndx] = val.elements[arrayNdx * scalarSize + ndx].float32; 395 } 396 else 397 { 398 // convert to floats. 399 for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++) 400 { 401 for (int ndx = 0; ndx < scalarSize; ndx++) 402 { 403 float v = (float)val.elements[arrayNdx * scalarSize + ndx].int32; 404 DE_ASSERT(val.elements[arrayNdx * scalarSize + ndx].int32 == (int)v); 405 scalars[repNdx * scalarSize + ndx] = v; 406 } 407 } 408 } 409 410 // Attribute name prefix. 411 string attribPrefix = ""; 412 // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)? 413 if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT)) 414 attribPrefix = "a_"; 415 416 // Input always given as attribute. 417 string attribName = attribPrefix + valueName; 418 int attribLoc = gl.getAttribLocation(programID, attribName.c_str()); 419 if (attribLoc == -1) 420 { 421 log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" 422 << TestLog::EndMessage; 423 continue; 424 } 425 426 if (isDataTypeMatrix(dataType)) 427 { 428 int numCols = getDataTypeMatrixNumColumns(dataType); 429 int numRows = getDataTypeMatrixNumRows(dataType); 430 DE_ASSERT(scalarSize == numCols * numRows); 431 432 for (int i = 0; i < numCols; i++) 433 vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, 434 static_cast<int>(scalarSize * sizeof(float)), 435 &scalars[i * numRows])); 436 } 437 else 438 { 439 DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || 440 isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType)); 441 vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0])); 442 } 443 444 GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array"); 445 } 446 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 447 { 448 // Set reference value. 449 string refName = string("ref_") + valueName; 450 setUniformValue(gl, programID, refName, val, arrayNdx); 451 GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms"); 452 } 453 else 454 { 455 DE_ASSERT(val.storageType == ShaderCase::Value::STORAGE_UNIFORM); 456 setUniformValue(gl, programID, valueName, val, arrayNdx); 457 GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms"); 458 } 459 } 460 461 // Clear. 462 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 463 gl.clear(GL_COLOR_BUFFER_BIT); 464 GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer"); 465 466 // Draw. 467 draw(m_renderCtx, program.getProgram(), (int)vertexArrays.size(), &vertexArrays[0], 468 pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])); 469 GLU_EXPECT_NO_ERROR(gl.getError(), "draw"); 470 471 // Read back results. 472 Surface surface(width, height); 473 glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess()); 474 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 475 476 float w = s_positions[3]; 477 int minY = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f); 478 int maxY = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f); 479 int minX = deCeilFloatToInt32(((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f); 480 int maxX = deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f); 481 482 if (!checkPixels(surface, minX, maxX, minY, maxY)) 483 { 484 log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx + 1) << " of " 485 << (int)m_valueBlocks.size() << ", sub-case " << arrayNdx + 1 << " of " << valueBlock.arrayLength 486 << "):" << TestLog::EndMessage; 487 488 log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage; 489 dumpValues(valueBlock, arrayNdx); 490 491 // Dump image on failure. 492 log << TestLog::Image("Result", "Rendered result image", surface); 493 494 gl.useProgram(0); 495 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 496 return false; 497 } 498 } 499 } 500 501 gl.useProgram(0); 502 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end"); 503 return true; 504 } 505 506 TestCase::IterateResult ShaderCase::iterate(void) 507 { 508 // Initialize state to pass. 509 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 510 511 bool executeOk = execute(); 512 513 DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : 514 m_testCtx.getTestResult() != QP_TEST_RESULT_PASS); 515 (void)executeOk; 516 return TestCase::STOP; 517 } 518 519 // This functions builds a matching vertex shader for a 'both' case, when 520 // the fragment shader is being tested. 521 // We need to build attributes and varyings for each 'input'. 522 string ShaderCase::genVertexShader(const ValueBlock& valueBlock) 523 { 524 ostringstream res; 525 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 526 const char* vtxIn = usesInout ? "in" : "attribute"; 527 const char* vtxOut = usesInout ? "out" : "varying"; 528 529 res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n"; 530 531 // Declarations (position + attribute/varying for each input). 532 res << "precision highp float;\n"; 533 res << "precision highp int;\n"; 534 res << "\n"; 535 res << vtxIn << " highp vec4 dEQP_Position;\n"; 536 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 537 { 538 const ShaderCase::Value& val = valueBlock.values[ndx]; 539 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 540 { 541 DataType floatType = getDataTypeFloatScalars(val.dataType); 542 const char* typeStr = getDataTypeName(floatType); 543 res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n"; 544 545 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 546 res << vtxOut << " " << typeStr << " " << val.valueName << ";\n"; 547 else 548 res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n"; 549 } 550 } 551 res << "\n"; 552 553 // Main function. 554 // - gl_Position = dEQP_Position; 555 // - for each input: write attribute directly to varying 556 res << "void main()\n"; 557 res << "{\n"; 558 res << " gl_Position = dEQP_Position;\n"; 559 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 560 { 561 const ShaderCase::Value& val = valueBlock.values[ndx]; 562 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 563 { 564 const string& name = val.valueName; 565 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 566 res << " " << name << " = a_" << name << ";\n"; 567 else 568 res << " v_" << name << " = a_" << name << ";\n"; 569 } 570 } 571 572 res << "}\n"; 573 return res.str(); 574 } 575 576 static void genCompareFunctions(ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes) 577 { 578 bool cmpTypeFound[TYPE_LAST]; 579 for (int i = 0; i < TYPE_LAST; i++) 580 cmpTypeFound[i] = false; 581 582 for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++) 583 { 584 const ShaderCase::Value& val = valueBlock.values[valueNdx]; 585 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 586 cmpTypeFound[(int)val.dataType] = true; 587 } 588 589 if (useFloatTypes) 590 { 591 if (cmpTypeFound[TYPE_BOOL]) 592 stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n"; 593 if (cmpTypeFound[TYPE_BOOL_VEC2]) 594 stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n"; 595 if (cmpTypeFound[TYPE_BOOL_VEC3]) 596 stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n"; 597 if (cmpTypeFound[TYPE_BOOL_VEC4]) 598 stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n"; 599 if (cmpTypeFound[TYPE_INT]) 600 stream << "bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= " 601 "float(b+1)); }\n"; 602 if (cmpTypeFound[TYPE_INT_VEC2]) 603 stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n"; 604 if (cmpTypeFound[TYPE_INT_VEC3]) 605 stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n"; 606 if (cmpTypeFound[TYPE_INT_VEC4]) 607 stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n"; 608 if (cmpTypeFound[TYPE_UINT]) 609 stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= " 610 "float(b+1)); }\n"; 611 if (cmpTypeFound[TYPE_UINT_VEC2]) 612 stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n"; 613 if (cmpTypeFound[TYPE_UINT_VEC3]) 614 stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n"; 615 if (cmpTypeFound[TYPE_UINT_VEC4]) 616 stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n"; 617 } 618 else 619 { 620 if (cmpTypeFound[TYPE_BOOL]) 621 stream << "bool isOk (bool a, bool b) { return (a == b); }\n"; 622 if (cmpTypeFound[TYPE_BOOL_VEC2]) 623 stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n"; 624 if (cmpTypeFound[TYPE_BOOL_VEC3]) 625 stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n"; 626 if (cmpTypeFound[TYPE_BOOL_VEC4]) 627 stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n"; 628 if (cmpTypeFound[TYPE_INT]) 629 stream << "bool isOk (int a, int b) { return (a == b); }\n"; 630 if (cmpTypeFound[TYPE_INT_VEC2]) 631 stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n"; 632 if (cmpTypeFound[TYPE_INT_VEC3]) 633 stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n"; 634 if (cmpTypeFound[TYPE_INT_VEC4]) 635 stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n"; 636 if (cmpTypeFound[TYPE_UINT]) 637 stream << "bool isOk (uint a, uint b) { return (a == b); }\n"; 638 if (cmpTypeFound[TYPE_UINT_VEC2]) 639 stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n"; 640 if (cmpTypeFound[TYPE_UINT_VEC3]) 641 stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n"; 642 if (cmpTypeFound[TYPE_UINT_VEC4]) 643 stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n"; 644 } 645 646 if (cmpTypeFound[TYPE_FLOAT]) 647 stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n"; 648 if (cmpTypeFound[TYPE_FLOAT_VEC2]) 649 stream 650 << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 651 if (cmpTypeFound[TYPE_FLOAT_VEC3]) 652 stream 653 << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 654 if (cmpTypeFound[TYPE_FLOAT_VEC4]) 655 stream 656 << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 657 658 if (cmpTypeFound[TYPE_FLOAT_MAT2]) 659 stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return " 660 "all(lessThanEqual(diff, vec2(eps))); }\n"; 661 if (cmpTypeFound[TYPE_FLOAT_MAT2X3]) 662 stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return " 663 "all(lessThanEqual(diff, vec3(eps))); }\n"; 664 if (cmpTypeFound[TYPE_FLOAT_MAT2X4]) 665 stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return " 666 "all(lessThanEqual(diff, vec4(eps))); }\n"; 667 if (cmpTypeFound[TYPE_FLOAT_MAT3X2]) 668 stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 669 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n"; 670 if (cmpTypeFound[TYPE_FLOAT_MAT3]) 671 stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 672 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n"; 673 if (cmpTypeFound[TYPE_FLOAT_MAT3X4]) 674 stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 675 "abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n"; 676 if (cmpTypeFound[TYPE_FLOAT_MAT4X2]) 677 stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 678 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n"; 679 if (cmpTypeFound[TYPE_FLOAT_MAT4X3]) 680 stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 681 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n"; 682 if (cmpTypeFound[TYPE_FLOAT_MAT4]) 683 stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), " 684 "max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n"; 685 } 686 687 static void genCompareOp(ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock, 688 const char* nonFloatNamePrefix, const char* checkVarName) 689 { 690 bool isFirstOutput = true; 691 692 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 693 { 694 const ShaderCase::Value& val = valueBlock.values[ndx]; 695 const char* valueName = val.valueName.c_str(); 696 697 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 698 { 699 // Check if we're only interested in one variable (then skip if not the right one). 700 if (checkVarName && !deStringEqual(valueName, checkVarName)) 701 continue; 702 703 // Prefix. 704 if (isFirstOutput) 705 { 706 output << "bool RES = "; 707 isFirstOutput = false; 708 } 709 else 710 output << "RES = RES && "; 711 712 // Generate actual comparison. 713 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 714 output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n"; 715 else 716 output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n"; 717 } 718 // \note Uniforms are already declared in shader. 719 } 720 721 if (isFirstOutput) 722 output << dstVec4Var << " = vec4(1.0);\n"; // \todo [petri] Should we give warning if not expect-failure case? 723 else 724 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n"; 725 } 726 727 string ShaderCase::genFragmentShader(const ValueBlock& valueBlock) 728 { 729 ostringstream shader; 730 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 731 const bool customColorOut = usesInout; 732 const char* fragIn = usesInout ? "in" : "varying"; 733 734 shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n"; 735 736 shader << "precision mediump float;\n"; 737 shader << "precision mediump int;\n"; 738 shader << "\n"; 739 740 if (customColorOut) 741 { 742 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 743 shader << "\n"; 744 } 745 746 genCompareFunctions(shader, valueBlock, true); 747 shader << "\n"; 748 749 // Declarations (varying, reference for each output). 750 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 751 { 752 const ShaderCase::Value& val = valueBlock.values[ndx]; 753 DataType floatType = getDataTypeFloatScalars(val.dataType); 754 const char* floatTypeStr = getDataTypeName(floatType); 755 const char* refTypeStr = getDataTypeName(val.dataType); 756 757 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 758 { 759 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 760 shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n"; 761 else 762 shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n"; 763 764 shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n"; 765 } 766 } 767 768 shader << "\n"; 769 shader << "void main()\n"; 770 shader << "{\n"; 771 772 shader << " "; 773 genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL); 774 775 shader << "}\n"; 776 return shader.str(); 777 } 778 779 // Specialize a shader for the vertex shader test case. 780 string ShaderCase::specializeVertexShader(const char* src, const ValueBlock& valueBlock) 781 { 782 ostringstream decl; 783 ostringstream setup; 784 ostringstream output; 785 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 786 const char* vtxIn = usesInout ? "in" : "attribute"; 787 const char* vtxOut = usesInout ? "out" : "varying"; 788 789 // Output (write out position). 790 output << "gl_Position = dEQP_Position;\n"; 791 792 // Declarations (position + attribute for each input, varying for each output). 793 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 794 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 795 { 796 const ShaderCase::Value& val = valueBlock.values[ndx]; 797 const char* valueName = val.valueName.c_str(); 798 DataType floatType = getDataTypeFloatScalars(val.dataType); 799 const char* floatTypeStr = getDataTypeName(floatType); 800 const char* refTypeStr = getDataTypeName(val.dataType); 801 802 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 803 { 804 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 805 { 806 decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n"; 807 } 808 else 809 { 810 decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n"; 811 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n"; 812 } 813 } 814 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 815 { 816 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 817 decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n"; 818 else 819 { 820 decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n"; 821 decl << refTypeStr << " " << valueName << ";\n"; 822 823 output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n"; 824 } 825 } 826 } 827 828 // Shader specialization. 829 map<string, string> params; 830 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 831 params.insert(pair<string, string>("SETUP", setup.str())); 832 params.insert(pair<string, string>("OUTPUT", output.str())); 833 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position")); 834 835 StringTemplate tmpl(src); 836 return tmpl.specialize(params); 837 } 838 839 // Specialize a shader for the fragment shader test case. 840 string ShaderCase::specializeFragmentShader(const char* src, const ValueBlock& valueBlock) 841 { 842 ostringstream decl; 843 ostringstream setup; 844 ostringstream output; 845 846 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 847 const bool customColorOut = usesInout; 848 const char* fragIn = usesInout ? "in" : "varying"; 849 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 850 851 genCompareFunctions(decl, valueBlock, false); 852 genCompareOp(output, fragColor, valueBlock, "", DE_NULL); 853 854 if (customColorOut) 855 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 856 857 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 858 { 859 const ShaderCase::Value& val = valueBlock.values[ndx]; 860 const char* valueName = val.valueName.c_str(); 861 DataType floatType = getDataTypeFloatScalars(val.dataType); 862 const char* floatTypeStr = getDataTypeName(floatType); 863 const char* refTypeStr = getDataTypeName(val.dataType); 864 865 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 866 { 867 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 868 decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n"; 869 else 870 { 871 decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n"; 872 std::string offset = 873 isDataTypeIntOrIVec(val.dataType) ? 874 " * 1.0025" : 875 ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation 876 setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset 877 << ");\n"; 878 } 879 } 880 else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 881 { 882 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n"; 883 decl << refTypeStr << " " << valueName << ";\n"; 884 } 885 } 886 887 /* \todo [2010-04-01 petri] Check all outputs. */ 888 889 // Shader specialization. 890 map<string, string> params; 891 params.insert(pair<string, string>("DECLARATIONS", decl.str())); 892 params.insert(pair<string, string>("SETUP", setup.str())); 893 params.insert(pair<string, string>("OUTPUT", output.str())); 894 params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor)); 895 896 StringTemplate tmpl(src); 897 return tmpl.specialize(params); 898 } 899 900 void ShaderCase::specializeShaders(const char* vertexSource, const char* fragmentSource, string& outVertexSource, 901 string& outFragmentSource, const ValueBlock& valueBlock) 902 { 903 const bool usesInout = usesShaderInoutQualifiers(m_targetVersion); 904 const bool customColorOut = usesInout; 905 906 // Vertex shader specialization. 907 { 908 ostringstream decl; 909 ostringstream setup; 910 const char* vtxIn = usesInout ? "in" : "attribute"; 911 912 decl << vtxIn << " highp vec4 dEQP_Position;\n"; 913 914 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 915 { 916 const ShaderCase::Value& val = valueBlock.values[ndx]; 917 const char* typeStr = getDataTypeName(val.dataType); 918 919 if (val.storageType == ShaderCase::Value::STORAGE_INPUT) 920 { 921 if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT) 922 { 923 decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n"; 924 } 925 else 926 { 927 DataType floatType = getDataTypeFloatScalars(val.dataType); 928 const char* floatTypeStr = getDataTypeName(floatType); 929 930 decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n"; 931 setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n"; 932 } 933 } 934 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos) 935 { 936 decl << "uniform " << typeStr << " " << val.valueName << ";\n"; 937 } 938 } 939 940 map<string, string> params; 941 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str())); 942 params.insert(pair<string, string>("VERTEX_SETUP", setup.str())); 943 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n"))); 944 StringTemplate tmpl(vertexSource); 945 outVertexSource = tmpl.specialize(params); 946 } 947 948 // Fragment shader specialization. 949 { 950 ostringstream decl; 951 ostringstream output; 952 const char* fragColor = customColorOut ? "dEQP_FragColor" : "gl_FragColor"; 953 954 genCompareFunctions(decl, valueBlock, false); 955 genCompareOp(output, fragColor, valueBlock, "", DE_NULL); 956 957 if (customColorOut) 958 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 959 960 for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++) 961 { 962 const ShaderCase::Value& val = valueBlock.values[ndx]; 963 const char* valueName = val.valueName.c_str(); 964 const char* refTypeStr = getDataTypeName(val.dataType); 965 966 if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT) 967 { 968 decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n"; 969 decl << refTypeStr << " " << valueName << ";\n"; 970 } 971 else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM && val.valueName.find('.') == string::npos) 972 { 973 decl << "uniform " << refTypeStr << " " << valueName << ";\n"; 974 } 975 } 976 977 map<string, string> params; 978 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str())); 979 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str())); 980 params.insert(pair<string, string>("FRAG_COLOR", fragColor)); 981 StringTemplate tmpl(fragmentSource); 982 outFragmentSource = tmpl.specialize(params); 983 } 984 } 985 986 void ShaderCase::dumpValues(const ValueBlock& valueBlock, int arrayNdx) 987 { 988 vector<vector<float> > attribValues; 989 990 int numValues = (int)valueBlock.values.size(); 991 for (int valNdx = 0; valNdx < numValues; valNdx++) 992 { 993 const ShaderCase::Value& val = valueBlock.values[valNdx]; 994 const char* valueName = val.valueName.c_str(); 995 DataType dataType = val.dataType; 996 int scalarSize = getDataTypeScalarSize(val.dataType); 997 ostringstream result; 998 999 result << " "; 1000 if (val.storageType == Value::STORAGE_INPUT) 1001 result << "input "; 1002 else if (val.storageType == Value::STORAGE_UNIFORM) 1003 result << "uniform "; 1004 else if (val.storageType == Value::STORAGE_OUTPUT) 1005 result << "expected "; 1006 1007 result << getDataTypeName(dataType) << " " << valueName << ":"; 1008 1009 if (isDataTypeScalar(dataType)) 1010 result << " "; 1011 if (isDataTypeVector(dataType)) 1012 result << " [ "; 1013 else if (isDataTypeMatrix(dataType)) 1014 result << "\n"; 1015 1016 if (isDataTypeScalarOrVector(dataType)) 1017 { 1018 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1019 { 1020 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx; 1021 const Value::Element& e = val.elements[elemNdx * scalarSize + scalarNdx]; 1022 result << ((scalarNdx != 0) ? ", " : ""); 1023 1024 if (isDataTypeFloatOrVec(dataType)) 1025 result << e.float32; 1026 else if (isDataTypeIntOrIVec(dataType)) 1027 result << e.int32; 1028 else if (isDataTypeBoolOrBVec(dataType)) 1029 result << (e.bool32 ? "true" : "false"); 1030 } 1031 } 1032 else if (isDataTypeMatrix(dataType)) 1033 { 1034 int numRows = getDataTypeMatrixNumRows(dataType); 1035 int numCols = getDataTypeMatrixNumColumns(dataType); 1036 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1037 { 1038 result << " [ "; 1039 for (int colNdx = 0; colNdx < numCols; colNdx++) 1040 { 1041 int elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx; 1042 float v = val.elements[elemNdx * scalarSize + rowNdx * numCols + colNdx].float32; 1043 result << ((colNdx == 0) ? "" : ", ") << v; 1044 } 1045 result << " ]\n"; 1046 } 1047 } 1048 1049 if (isDataTypeScalar(dataType)) 1050 result << "\n"; 1051 else if (isDataTypeVector(dataType)) 1052 result << " ]\n"; 1053 1054 m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage; 1055 } 1056 } 1057 1058 } // sl 1059 } // deqp 1060