1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 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 Shader API tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fShaderApiTests.hpp" 25 #include "es3fApiCase.hpp" 26 #include "tcuTestLog.hpp" 27 28 #include "gluRenderContext.hpp" 29 #include "gluShaderProgram.hpp" 30 #include "gluShaderUtil.hpp" 31 #include "gluDrawUtil.hpp" 32 #include "gluContextInfo.hpp" 33 #include "gluCallLogWrapper.hpp" 34 35 #include "glwFunctions.hpp" 36 #include "glwDefs.hpp" 37 #include "glwEnums.hpp" 38 39 #include "deString.h" 40 41 #include "deRandom.hpp" 42 #include "deStringUtil.hpp" 43 44 #include <string> 45 #include <sstream> 46 #include <vector> 47 #include <map> 48 49 using namespace glw; // GL types 50 51 namespace deqp 52 { 53 namespace gles3 54 { 55 namespace Functional 56 { 57 58 using tcu::TestLog; 59 60 namespace 61 { 62 63 enum ShaderSourceCaseFlags 64 { 65 CASE_EXPLICIT_SOURCE_LENGTHS = 1, 66 CASE_RANDOM_NULL_TERMINATED = 2 67 }; 68 69 struct ShaderSources 70 { 71 std::vector<std::string> strings; 72 std::vector<int> lengths; 73 }; 74 75 // Simple shaders 76 77 const char* getSimpleShaderSource (const glu::ShaderType shaderType) 78 { 79 const char* simpleVertexShaderSource = 80 "#version 300 es\n" 81 "void main (void)\n" 82 "{\n" 83 " gl_Position = vec4(0.0);\n" 84 "}\n"; 85 86 const char* simpleFragmentShaderSource = 87 "#version 300 es\n" 88 "layout(location = 0) out mediump vec4 o_fragColor;\n" 89 "void main (void)\n" 90 "{\n" 91 " o_fragColor = vec4(0.0);\n" 92 "}\n"; 93 94 switch (shaderType) 95 { 96 case glu::SHADERTYPE_VERTEX: 97 return simpleVertexShaderSource; 98 case glu::SHADERTYPE_FRAGMENT: 99 return simpleFragmentShaderSource; 100 default: 101 DE_ASSERT(DE_FALSE); 102 } 103 104 return 0; 105 } 106 107 void setShaderSources (glu::Shader& shader, const ShaderSources& sources) 108 { 109 std::vector<const char*> cStrings (sources.strings.size(), 0); 110 111 for (size_t ndx = 0; ndx < sources.strings.size(); ndx++) 112 cStrings[ndx] = sources.strings[ndx].c_str(); 113 114 if (sources.lengths.size() > 0) 115 shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]); 116 else 117 shader.setSources((int)cStrings.size(), &cStrings[0], 0); 118 } 119 120 void sliceSourceString (const std::string& in, ShaderSources& out, const int numSlices, const size_t paddingLength = 0) 121 { 122 DE_ASSERT(numSlices > 0); 123 124 const size_t sliceSize = in.length() / numSlices; 125 const size_t sliceSizeRemainder = in.length() - (sliceSize * numSlices); 126 const std::string padding (paddingLength, 'E'); 127 128 for (int ndx = 0; ndx < numSlices; ndx++) 129 { 130 out.strings.push_back(in.substr(ndx * sliceSize, sliceSize) + padding); 131 132 if (paddingLength > 0) 133 out.lengths.push_back((int)sliceSize); 134 } 135 136 if (sliceSizeRemainder > 0) 137 { 138 const std::string lastString = in.substr(numSlices * sliceSize); 139 const int lastStringLength = (int)lastString.length(); 140 141 out.strings.push_back(lastString + padding); 142 143 if (paddingLength > 0) 144 out.lengths.push_back(lastStringLength); 145 } 146 } 147 148 void queryShaderInfo (glu::RenderContext& renderCtx, deUint32 shader, glu::ShaderInfo& info) 149 { 150 const glw::Functions& gl = renderCtx.getFunctions(); 151 152 info.compileOk = false; 153 info.compileTimeUs = 0; 154 info.infoLog.clear(); 155 156 // Query source, status & log. 157 { 158 int compileStatus = 0; 159 int sourceLen = 0; 160 int infoLogLen = 0; 161 int unusedLen; 162 163 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); 164 gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen); 165 gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen); 166 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()"); 167 168 info.compileOk = compileStatus != GL_FALSE; 169 170 if (sourceLen > 0) 171 { 172 std::vector<char> source(sourceLen); 173 gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]); 174 info.source = std::string(&source[0], sourceLen); 175 } 176 177 if (infoLogLen > 0) 178 { 179 std::vector<char> infoLog(infoLogLen); 180 gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]); 181 info.infoLog = std::string(&infoLog[0], infoLogLen); 182 } 183 } 184 } 185 186 // Draw test quad 187 188 void drawWithProgram (glu::RenderContext& renderCtx, deUint32 program) 189 { 190 const glw::Functions& gl = renderCtx.getFunctions(); 191 192 const float position[] = 193 { 194 -1.0f, -1.0f, 0.0f, 1.0f, 195 -1.0f, +1.0f, 0.0f, 1.0f, 196 +1.0f, -1.0f, 0.0f, 1.0f, 197 +1.0f, +1.0f, 0.0f, 1.0f 198 }; 199 const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 200 201 gl.useProgram(program); 202 203 { 204 glu::VertexArrayBinding vertexArrays[] = 205 { 206 glu::va::Float("a_position", 4, 4, 0, &position[0]) 207 }; 208 glu::draw(renderCtx, program, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0])); 209 } 210 211 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw test quad"); 212 } 213 214 // Shader source generator 215 216 class SourceGenerator 217 { 218 public: 219 virtual ~SourceGenerator (void) {} 220 221 virtual std::string next (const glu::ShaderType shaderType) = 0; 222 virtual bool finished (const glu::ShaderType shaderType) const = 0; 223 }; 224 225 class ConstantShaderGenerator : public SourceGenerator 226 { 227 public: 228 ConstantShaderGenerator (de::Random& rnd) : m_rnd(rnd) {} 229 ~ConstantShaderGenerator (void) {} 230 231 bool finished (const glu::ShaderType shaderType) const { DE_UNREF(shaderType); return false; } 232 233 std::string next (const glu::ShaderType shaderType); 234 235 private: 236 de::Random m_rnd; 237 }; 238 239 std::string ConstantShaderGenerator::next (const glu::ShaderType shaderType) 240 { 241 DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT); 242 243 const float value = m_rnd.getFloat(0.0f, 1.0f); 244 const std::string valueString = de::toString(value); 245 const std::string outputName = (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "o_fragColor"; 246 247 std::ostringstream out; 248 249 out << "#version 300 es\n"; 250 251 if (shaderType == glu::SHADERTYPE_FRAGMENT) 252 out << "layout(location = 0) out mediump vec4 o_fragColor;\n"; 253 254 out << "void main (void)\n"; 255 out << "{\n"; 256 out << " " << outputName << " = vec4(" << valueString << ");\n"; 257 out << "}\n"; 258 259 return out.str(); 260 } 261 262 // Shader allocation utility 263 264 class ShaderAllocator 265 { 266 public: 267 ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator); 268 ~ShaderAllocator (void); 269 270 bool hasShader (const glu::ShaderType shaderType); 271 272 void setSource (const glu::ShaderType shaderType); 273 274 glu::Shader& createShader (const glu::ShaderType shaderType); 275 void deleteShader (const glu::ShaderType shaderType); 276 277 glu::Shader& get (const glu::ShaderType shaderType) { DE_ASSERT(hasShader(shaderType)); return *m_shaders[shaderType]; } 278 279 private: 280 const glu::RenderContext& m_context; 281 SourceGenerator& m_srcGen; 282 std::map<glu::ShaderType, glu::Shader*> m_shaders; 283 }; 284 285 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator) 286 : m_context (context) 287 , m_srcGen (generator) 288 { 289 } 290 291 ShaderAllocator::~ShaderAllocator (void) 292 { 293 for (std::map<glu::ShaderType, glu::Shader*>::iterator shaderIter = m_shaders.begin(); shaderIter != m_shaders.end(); shaderIter++) 294 delete shaderIter->second; 295 m_shaders.clear(); 296 } 297 298 bool ShaderAllocator::hasShader (const glu::ShaderType shaderType) 299 { 300 if (m_shaders.find(shaderType) != m_shaders.end()) 301 return true; 302 else 303 return false; 304 } 305 306 glu::Shader& ShaderAllocator::createShader (const glu::ShaderType shaderType) 307 { 308 DE_ASSERT(!this->hasShader(shaderType)); 309 310 glu::Shader* const shader = new glu::Shader(m_context, shaderType); 311 312 m_shaders[shaderType] = shader; 313 this->setSource(shaderType); 314 315 return *shader; 316 } 317 318 void ShaderAllocator::deleteShader (const glu::ShaderType shaderType) 319 { 320 DE_ASSERT(this->hasShader(shaderType)); 321 322 delete m_shaders[shaderType]; 323 m_shaders.erase(shaderType); 324 } 325 326 void ShaderAllocator::setSource (const glu::ShaderType shaderType) 327 { 328 DE_ASSERT(this->hasShader(shaderType)); 329 DE_ASSERT(!m_srcGen.finished(shaderType)); 330 331 const std::string source = m_srcGen.next(shaderType); 332 const char* const cSource = source.c_str(); 333 334 m_shaders[shaderType]->setSources(1, &cSource, 0); 335 } 336 337 // Logging utilities 338 339 void logShader (TestLog& log, glu::RenderContext& renderCtx, glu::Shader& shader) 340 { 341 glu::ShaderInfo info; 342 343 queryShaderInfo(renderCtx, shader.getShader(), info); 344 345 log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog); 346 } 347 348 void logProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, ShaderAllocator& shaders) 349 { 350 log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog()); 351 352 for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++) 353 { 354 const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt; 355 356 if (shaders.hasShader(shaderType)) 357 logShader(log, renderCtx, shaders.get(shaderType)); 358 } 359 360 log << TestLog::EndShaderProgram; 361 } 362 363 void logVertexFragmentProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, glu::Shader& vertShader, glu::Shader& fragShader) 364 { 365 DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT); 366 367 log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog()); 368 369 logShader(log, renderCtx, vertShader); 370 logShader(log, renderCtx, fragShader); 371 372 log << TestLog::EndShaderProgram; 373 } 374 375 } // anonymous 376 377 // Simple glCreateShader() case 378 379 class CreateShaderCase : public ApiCase 380 { 381 public: 382 CreateShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 383 : ApiCase (context, name, desc) 384 , m_shaderType (shaderType) 385 { 386 } 387 388 void test (void) 389 { 390 const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType)); 391 392 TCU_CHECK(shaderObject != 0); 393 394 glDeleteShader(shaderObject); 395 } 396 397 private: 398 const glu::ShaderType m_shaderType; 399 }; 400 401 // Simple glCompileShader() case 402 403 class CompileShaderCase : public ApiCase 404 { 405 public: 406 CompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 407 : ApiCase (context, name, desc) 408 , m_shaderType (shaderType) 409 { 410 } 411 412 bool checkCompileStatus (const GLuint shaderObject) 413 { 414 GLint compileStatus = -1; 415 glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus); 416 GLU_CHECK(); 417 418 return (compileStatus == GL_TRUE); 419 } 420 421 void test (void) 422 { 423 const char* shaderSource = getSimpleShaderSource(m_shaderType); 424 const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType)); 425 426 TCU_CHECK(shaderObject != 0); 427 428 glShaderSource(shaderObject, 1, &shaderSource, 0); 429 glCompileShader(shaderObject); 430 431 TCU_CHECK(checkCompileStatus(shaderObject)); 432 433 glDeleteShader(shaderObject); 434 } 435 436 private: 437 const glu::ShaderType m_shaderType; 438 }; 439 440 // Base class for simple program API tests 441 442 class SimpleProgramCase : public ApiCase 443 { 444 public: 445 SimpleProgramCase (Context& context, const char* name, const char* desc) 446 : ApiCase (context, name, desc) 447 , m_vertShader (0) 448 , m_fragShader (0) 449 , m_program (0) 450 { 451 } 452 453 virtual ~SimpleProgramCase (void) 454 { 455 } 456 457 virtual void compileShaders (void) 458 { 459 const char* vertSource = getSimpleShaderSource(glu::SHADERTYPE_VERTEX); 460 const char* fragSource = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT); 461 462 const GLuint vertShader = glCreateShader(GL_VERTEX_SHADER); 463 const GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); 464 465 TCU_CHECK(vertShader != 0); 466 TCU_CHECK(fragShader != 0); 467 468 glShaderSource(vertShader, 1, &vertSource, 0); 469 glCompileShader(vertShader); 470 471 glShaderSource(fragShader, 1, &fragSource, 0); 472 glCompileShader(fragShader); 473 474 GLU_CHECK(); 475 476 m_vertShader = vertShader; 477 m_fragShader = fragShader; 478 } 479 480 void linkProgram (void) 481 { 482 const GLuint program = glCreateProgram(); 483 484 TCU_CHECK(program != 0); 485 486 glAttachShader(program, m_vertShader); 487 glAttachShader(program, m_fragShader); 488 GLU_CHECK(); 489 490 glLinkProgram(program); 491 492 m_program = program; 493 } 494 495 void cleanup (void) 496 { 497 glDeleteShader(m_vertShader); 498 glDeleteShader(m_fragShader); 499 glDeleteProgram(m_program); 500 } 501 502 protected: 503 GLuint m_vertShader; 504 GLuint m_fragShader; 505 GLuint m_program; 506 }; 507 508 // glDeleteShader() case 509 510 class DeleteShaderCase : public SimpleProgramCase 511 { 512 public: 513 DeleteShaderCase (Context& context, const char* name, const char* desc) 514 : SimpleProgramCase (context, name, desc) 515 { 516 } 517 518 bool checkDeleteStatus(GLuint shader) 519 { 520 GLint deleteStatus = -1; 521 glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus); 522 GLU_CHECK(); 523 524 return (deleteStatus == GL_TRUE); 525 } 526 527 void deleteShaders (void) 528 { 529 glDeleteShader(m_vertShader); 530 glDeleteShader(m_fragShader); 531 GLU_CHECK(); 532 } 533 534 void test (void) 535 { 536 compileShaders(); 537 linkProgram(); 538 GLU_CHECK(); 539 540 deleteShaders(); 541 542 TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader)); 543 544 glDeleteProgram(m_program); 545 546 TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader))); 547 } 548 }; 549 550 // Simple glLinkProgram() case 551 552 class LinkVertexFragmentCase : public SimpleProgramCase 553 { 554 public: 555 LinkVertexFragmentCase (Context& context, const char* name, const char* desc) 556 : SimpleProgramCase (context, name, desc) 557 { 558 } 559 560 bool checkLinkStatus (const GLuint programObject) 561 { 562 GLint linkStatus = -1; 563 glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus); 564 GLU_CHECK(); 565 566 return (linkStatus == GL_TRUE); 567 } 568 569 void test (void) 570 { 571 compileShaders(); 572 linkProgram(); 573 574 GLU_CHECK_MSG("Linking failed."); 575 TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE."); 576 577 cleanup(); 578 } 579 }; 580 581 class ShaderSourceReplaceCase : public ApiCase 582 { 583 public: 584 ShaderSourceReplaceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 585 : ApiCase (context, name, desc) 586 , m_shaderType (shaderType) 587 { 588 } 589 590 std::string generateFirstSource (void) 591 { 592 return getSimpleShaderSource(m_shaderType); 593 } 594 595 std::string generateSecondSource (void) 596 { 597 std::ostringstream out; 598 599 out << "#version 300 es\n"; 600 out << "precision mediump float;\n"; 601 602 if (m_shaderType == glu::SHADERTYPE_FRAGMENT) 603 out << "layout(location = 0) out mediump vec4 o_fragColor;\n"; 604 605 out << "void main()\n"; 606 out << "{\n"; 607 out << " float variable = 1.0f;\n"; 608 609 if (m_shaderType == glu::SHADERTYPE_VERTEX) out << " gl_Position = vec4(variable);\n"; 610 else if (m_shaderType == glu::SHADERTYPE_FRAGMENT) out << " o_fragColor = vec4(variable);\n"; 611 612 out << "}\n"; 613 614 return out.str(); 615 } 616 617 GLint getSourceLength (glu::Shader& shader) 618 { 619 GLint sourceLength = 0; 620 glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength); 621 GLU_CHECK(); 622 623 return sourceLength; 624 } 625 626 std::string readSource (glu::Shader& shader) 627 { 628 const GLint sourceLength = getSourceLength(shader); 629 std::vector<char> sourceBuffer (sourceLength + 1); 630 631 glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]); 632 633 return std::string(&sourceBuffer[0]); 634 } 635 636 void verifyShaderSourceReplaced (glu::Shader& shader, const std::string& firstSource, const std::string& secondSource) 637 { 638 TestLog& log = m_testCtx.getLog(); 639 const std::string result = readSource(shader); 640 641 if (result == firstSource) 642 { 643 log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage; 644 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced"); 645 } 646 else if (result != secondSource) 647 { 648 log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage; 649 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source"); 650 } 651 } 652 653 void test (void) 654 { 655 TestLog& log = m_testCtx.getLog(); 656 657 glu::Shader shader (m_context.getRenderContext(), m_shaderType); 658 659 const std::string firstSourceStr = generateFirstSource(); 660 const std::string secondSourceStr = generateSecondSource(); 661 662 const char* firstSource = firstSourceStr.c_str(); 663 const char* secondSource = secondSourceStr.c_str(); 664 665 log << TestLog::Message << "Setting shader source." << TestLog::EndMessage; 666 667 shader.setSources(1, &firstSource, 0); 668 GLU_CHECK(); 669 670 log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage; 671 672 shader.setSources(1, &secondSource, 0); 673 GLU_CHECK(); 674 675 verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr); 676 } 677 678 private: 679 glu::ShaderType m_shaderType; 680 }; 681 682 // glShaderSource() split source case 683 684 class ShaderSourceSplitCase : public ApiCase 685 { 686 public: 687 ShaderSourceSplitCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType, const int numSlices, const deUint32 flags = 0) 688 : ApiCase (context, name, desc) 689 , m_rnd (deStringHash(getName()) ^ 0x4fb2337d) 690 , m_shaderType (shaderType) 691 , m_numSlices (numSlices) 692 , m_explicitLengths ((flags & CASE_EXPLICIT_SOURCE_LENGTHS) != 0) 693 , m_randomNullTerm ((flags & CASE_RANDOM_NULL_TERMINATED) != 0) 694 { 695 DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT); 696 } 697 698 virtual ~ShaderSourceSplitCase (void) 699 { 700 } 701 702 std::string generateFullSource (void) 703 { 704 std::ostringstream out; 705 706 out << "#version 300 es\n"; 707 out << "precision mediump float;\n"; 708 709 if (m_shaderType == glu::SHADERTYPE_FRAGMENT) 710 out << "layout(location = 0) out mediump vec4 o_fragColor;\n"; 711 712 out << "void main()\n"; 713 out << "{\n"; 714 out << " float variable = 1.0f;\n"; 715 716 if (m_shaderType == glu::SHADERTYPE_VERTEX) out << " gl_Position = vec4(variable);\n"; 717 else if (m_shaderType == glu::SHADERTYPE_FRAGMENT) out << " o_fragColor = vec4(variable);\n"; 718 719 out << "}\n"; 720 721 return out.str(); 722 } 723 724 void insertRandomNullTermStrings (ShaderSources& sources) 725 { 726 const int numInserts = de::max(m_numSlices >> 2, 1); 727 std::vector<int> indices (sources.strings.size(), 0); 728 729 DE_ASSERT(sources.lengths.size() > 0); 730 DE_ASSERT(sources.lengths.size() == sources.strings.size()); 731 732 for (int i = 0; i < (int)sources.strings.size(); i++) 733 indices[i] = i; 734 735 m_rnd.shuffle(indices.begin(), indices.end()); 736 737 for (int i = 0; i < numInserts; i++) 738 { 739 const int ndx = indices[i]; 740 const int unpaddedLength = sources.lengths[ndx]; 741 const std::string unpaddedString = sources.strings[ndx].substr(0, unpaddedLength); 742 743 sources.strings[ndx] = unpaddedString; 744 sources.lengths[ndx] = m_rnd.getInt(-10, -1); 745 } 746 } 747 748 void generateSources (ShaderSources& sources) 749 { 750 const size_t paddingLength = (m_explicitLengths ? 10 : 0); 751 std::string str = generateFullSource(); 752 753 sliceSourceString(str, sources, m_numSlices, paddingLength); 754 755 if (m_randomNullTerm) 756 insertRandomNullTermStrings(sources); 757 } 758 759 void buildProgram (glu::Shader& shader) 760 { 761 TestLog& log = m_testCtx.getLog(); 762 glu::RenderContext& renderCtx = m_context.getRenderContext(); 763 764 const glu::ShaderType supportShaderType = (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT); 765 const char* supportShaderSource = getSimpleShaderSource(supportShaderType); 766 glu::Shader supportShader (renderCtx, supportShaderType); 767 768 glu::Program program (renderCtx); 769 770 supportShader.setSources(1, &supportShaderSource, 0); 771 supportShader.compile(); 772 773 program.attachShader(shader.getShader()); 774 program.attachShader(supportShader.getShader()); 775 776 program.link(); 777 778 if (m_shaderType == glu::SHADERTYPE_VERTEX) 779 logVertexFragmentProgram(log, renderCtx, program, shader, supportShader); 780 else 781 logVertexFragmentProgram(log, renderCtx, program, supportShader, shader); 782 } 783 784 void test (void) 785 { 786 TestLog& log = m_testCtx.getLog(); 787 glu::RenderContext& renderCtx = m_context.getRenderContext(); 788 789 ShaderSources sources; 790 glu::Shader shader (renderCtx, m_shaderType); 791 792 generateSources(sources); 793 setShaderSources(shader, sources); 794 shader.compile(); 795 796 buildProgram(shader); 797 798 if (!shader.getCompileStatus()) 799 { 800 log << TestLog::Message << "Compilation failed." << TestLog::EndMessage; 801 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 802 } 803 } 804 805 private: 806 de::Random m_rnd; 807 808 const glu::ShaderType m_shaderType; 809 const int m_numSlices; 810 811 const bool m_explicitLengths; 812 const bool m_randomNullTerm; 813 }; 814 815 // Base class for program state persistence cases 816 817 class ProgramStateCase : public ApiCase 818 { 819 public: 820 ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType); 821 virtual ~ProgramStateCase (void) {} 822 823 void buildProgram (glu::Program& program, ShaderAllocator& shaders); 824 void verify (glu::Program& program, const glu::ProgramInfo& reference); 825 826 void test (void); 827 828 virtual void executeForProgram (glu::Program& program, ShaderAllocator& shaders) = 0; 829 830 protected: 831 de::Random m_rnd; 832 const glu::ShaderType m_shaderType; 833 }; 834 835 ProgramStateCase::ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 836 : ApiCase (context, name, desc) 837 , m_rnd (deStringHash(name) ^ 0x713de0ca) 838 , m_shaderType (shaderType) 839 { 840 DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT); 841 } 842 843 void ProgramStateCase::buildProgram (glu::Program& program, ShaderAllocator& shaders) 844 { 845 TestLog& log = m_testCtx.getLog(); 846 847 glu::Shader& vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX); 848 glu::Shader& fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT); 849 850 vertShader.compile(); 851 fragShader.compile(); 852 853 program.attachShader(vertShader.getShader()); 854 program.attachShader(fragShader.getShader()); 855 program.link(); 856 857 logProgram(log, m_context.getRenderContext(), program, shaders); 858 } 859 860 void ProgramStateCase::verify (glu::Program& program, const glu::ProgramInfo& reference) 861 { 862 TestLog& log = m_testCtx.getLog(); 863 const glu::ProgramInfo& programInfo = program.getInfo(); 864 865 if (!programInfo.linkOk) 866 { 867 log << TestLog::Message << "Fail, link status may only change as a result of linking or loading a program binary." << TestLog::EndMessage; 868 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed"); 869 } 870 871 if (programInfo.linkTimeUs != reference.linkTimeUs) 872 { 873 log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage; 874 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed"); 875 } 876 877 if (programInfo.infoLog != reference.infoLog) 878 { 879 log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage; 880 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed"); 881 } 882 } 883 884 void ProgramStateCase::test (void) 885 { 886 TestLog& log = m_testCtx.getLog(); 887 glu::RenderContext& renderCtx = m_context.getRenderContext(); 888 889 ConstantShaderGenerator sourceGen (m_rnd); 890 891 ShaderAllocator shaders (renderCtx, sourceGen); 892 glu::Program program (renderCtx); 893 894 buildProgram(program, shaders); 895 896 if (program.getLinkStatus()) 897 { 898 glu::ProgramInfo programInfo = program.getInfo(); 899 900 executeForProgram(program, shaders); 901 902 verify(program, programInfo); 903 904 logProgram(log, renderCtx, program, shaders); 905 } 906 else 907 { 908 log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage; 909 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed"); 910 } 911 } 912 913 // Program state case utilities 914 915 namespace 916 { 917 918 template<class T> 919 void addProgramStateCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc) 920 { 921 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 922 { 923 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 924 const std::string shaderTypeName = getShaderTypeName(shaderType); 925 926 const std::string caseName = name + "_" + shaderTypeName; 927 const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader."; 928 929 group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType)); 930 } 931 } 932 933 } // anonymous 934 935 // Specialized program state cases 936 937 class ProgramStateDetachShaderCase : public ProgramStateCase 938 { 939 public: 940 ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 941 : ProgramStateCase (context, name, desc, shaderType) 942 { 943 } 944 945 virtual ~ProgramStateDetachShaderCase (void) 946 { 947 } 948 949 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 950 { 951 TestLog& log = m_testCtx.getLog(); 952 glu::Shader& caseShader = shaders.get(m_shaderType); 953 954 log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 955 program.detachShader(caseShader.getShader()); 956 } 957 }; 958 959 class ProgramStateReattachShaderCase : public ProgramStateCase 960 { 961 public: 962 ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 963 : ProgramStateCase (context, name, desc, shaderType) 964 { 965 } 966 967 virtual ~ProgramStateReattachShaderCase (void) 968 { 969 } 970 971 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 972 { 973 TestLog& log = m_testCtx.getLog(); 974 glu::Shader& caseShader = shaders.get(m_shaderType); 975 976 log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 977 program.detachShader(caseShader.getShader()); 978 program.attachShader(caseShader.getShader()); 979 } 980 }; 981 982 class ProgramStateDeleteShaderCase : public ProgramStateCase 983 { 984 public: 985 ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 986 : ProgramStateCase (context, name, desc, shaderType) 987 { 988 } 989 990 virtual ~ProgramStateDeleteShaderCase (void) 991 { 992 } 993 994 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 995 { 996 TestLog& log = m_testCtx.getLog(); 997 glu::Shader& caseShader = shaders.get(m_shaderType); 998 999 log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1000 program.detachShader(caseShader.getShader()); 1001 shaders.deleteShader(m_shaderType); 1002 } 1003 }; 1004 1005 class ProgramStateReplaceShaderCase : public ProgramStateCase 1006 { 1007 public: 1008 ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1009 : ProgramStateCase (context, name, desc, shaderType) 1010 { 1011 } 1012 1013 virtual ~ProgramStateReplaceShaderCase (void) 1014 { 1015 } 1016 1017 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1018 { 1019 TestLog& log = m_testCtx.getLog(); 1020 glu::Shader& caseShader = shaders.get(m_shaderType); 1021 1022 log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1023 program.detachShader(caseShader.getShader()); 1024 shaders.deleteShader(m_shaderType); 1025 program.attachShader(shaders.createShader(m_shaderType).getShader()); 1026 } 1027 }; 1028 1029 class ProgramStateRecompileShaderCase : public ProgramStateCase 1030 { 1031 public: 1032 ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1033 : ProgramStateCase (context, name, desc, shaderType) 1034 { 1035 } 1036 1037 virtual ~ProgramStateRecompileShaderCase (void) 1038 { 1039 } 1040 1041 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1042 { 1043 TestLog& log = m_testCtx.getLog(); 1044 glu::Shader& caseShader = shaders.get(m_shaderType); 1045 1046 log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1047 caseShader.compile(); 1048 DE_UNREF(program); 1049 } 1050 }; 1051 1052 class ProgramStateReplaceSourceCase : public ProgramStateCase 1053 { 1054 public: 1055 ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1056 : ProgramStateCase (context, name, desc, shaderType) 1057 { 1058 } 1059 1060 virtual ~ProgramStateReplaceSourceCase (void) 1061 { 1062 } 1063 1064 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1065 { 1066 TestLog& log = m_testCtx.getLog(); 1067 glu::Shader& caseShader = shaders.get(m_shaderType); 1068 1069 log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage; 1070 shaders.setSource(m_shaderType); 1071 caseShader.compile(); 1072 DE_UNREF(program); 1073 } 1074 }; 1075 1076 // Program binary utilities 1077 1078 namespace 1079 { 1080 1081 struct ProgramBinary 1082 { 1083 GLenum format; 1084 std::vector<deUint8> data; 1085 }; 1086 1087 bool programBinariesEqual (const ProgramBinary& first, const ProgramBinary& second) 1088 { 1089 if ((first.format != second.format) || (first.data.size() != second.data.size())) 1090 return false; 1091 1092 return std::equal(first.data.begin(), first.data.end(), second.data.begin()); 1093 } 1094 1095 } // anonymous 1096 1097 // Base class for program binary cases 1098 1099 class ProgramBinaryCase : public TestCase, protected glu::CallLogWrapper 1100 { 1101 public: 1102 ProgramBinaryCase (Context& context, const char* name, const char* desc); 1103 virtual ~ProgramBinaryCase (void); 1104 1105 void getBinaryFormats (std::vector<GLenum>& out); 1106 bool isFormatSupported (const glw::GLenum format) const; 1107 1108 void getProgramBinary (ProgramBinary& out, GLuint program); 1109 void loadProgramBinary (ProgramBinary& binary, GLuint program); 1110 1111 void verifyProgramBinary (ProgramBinary& binary); 1112 1113 void init (void); 1114 IterateResult iterate (void); 1115 1116 virtual void test (void) = 0; 1117 1118 protected: 1119 std::vector<GLenum> m_formats; 1120 }; 1121 1122 ProgramBinaryCase::ProgramBinaryCase (Context& context, const char* name, const char* desc) 1123 : TestCase (context, name, desc) 1124 , CallLogWrapper (context.getRenderContext().getFunctions(), context.getTestContext().getLog()) 1125 { 1126 } 1127 1128 ProgramBinaryCase::~ProgramBinaryCase (void) 1129 { 1130 } 1131 1132 void ProgramBinaryCase::getBinaryFormats (std::vector<GLenum>& out) 1133 { 1134 GLint numFormats = -1; 1135 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats); 1136 1137 out.clear(); 1138 1139 if (numFormats > 0) 1140 { 1141 out.resize(numFormats, 0); 1142 1143 glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, (GLint*)&out[0]); 1144 } 1145 } 1146 1147 bool ProgramBinaryCase::isFormatSupported (const glw::GLenum format) const 1148 { 1149 return (std::find(m_formats.begin(), m_formats.end(), format) != m_formats.end()); 1150 } 1151 1152 void ProgramBinaryCase::getProgramBinary (ProgramBinary& out, GLuint program) 1153 { 1154 GLint binaryLength = -1; 1155 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength); 1156 1157 if (binaryLength > 0) 1158 { 1159 GLsizei actualLength; 1160 GLenum format; 1161 1162 out.data.clear(); 1163 out.data.resize(binaryLength, 0); 1164 1165 GLU_CHECK_CALL(glGetProgramBinary(program, (GLsizei)out.data.size(), &actualLength, &format, &(out.data[0]))); 1166 1167 TCU_CHECK(actualLength == binaryLength); 1168 1169 out.format = format; 1170 } 1171 } 1172 1173 void ProgramBinaryCase::loadProgramBinary (ProgramBinary& binary, GLuint program) 1174 { 1175 glProgramBinary(program, binary.format, &binary.data[0], (GLsizei)binary.data.size()); 1176 GLU_CHECK_MSG("Failed to load program binary."); 1177 } 1178 1179 void ProgramBinaryCase::verifyProgramBinary (ProgramBinary& binary) 1180 { 1181 TestLog& log = m_testCtx.getLog(); 1182 1183 if (!isFormatSupported(binary.format)) 1184 { 1185 log << TestLog::Message << "Program binary format " << binary.format << " is not among the supported formats reported by the platform." << TestLog::EndMessage; 1186 1187 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid format"); 1188 } 1189 } 1190 1191 void ProgramBinaryCase::init (void) 1192 { 1193 getBinaryFormats(m_formats); 1194 } 1195 1196 tcu::TestNode::IterateResult ProgramBinaryCase::iterate (void) 1197 { 1198 TestLog& log = m_testCtx.getLog(); 1199 1200 if (m_formats.empty()) 1201 { 1202 log << TestLog::Message << "No program binary formats are supported." << TestLog::EndMessage; 1203 1204 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); 1205 } 1206 else 1207 { 1208 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1209 1210 enableLogging(true); 1211 test(); 1212 } 1213 1214 return STOP; 1215 } 1216 1217 // Simple program binary case 1218 1219 class ProgramBinarySimpleCase : public ProgramBinaryCase 1220 { 1221 public: 1222 ProgramBinarySimpleCase (Context& context, const char* name, const char* desc) 1223 : ProgramBinaryCase(context, name, desc) 1224 { 1225 } 1226 1227 virtual ~ProgramBinarySimpleCase (void) 1228 { 1229 } 1230 1231 void test (void) 1232 { 1233 const std::string vertSrc = getSimpleShaderSource(glu::SHADERTYPE_VERTEX); 1234 const std::string fragSrc = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT); 1235 1236 const glu::ProgramSources sources = glu::makeVtxFragSources(vertSrc, fragSrc); 1237 1238 glu::ShaderProgram program (m_context.getRenderContext(), sources); 1239 1240 if (program.isOk()) 1241 { 1242 ProgramBinary binary; 1243 1244 getProgramBinary(binary, program.getProgram()); 1245 verifyProgramBinary(binary); 1246 } 1247 } 1248 }; 1249 1250 // Program binary uniform reset case 1251 1252 class ProgramBinaryUniformResetCase : public ProgramBinaryCase 1253 { 1254 public: 1255 ProgramBinaryUniformResetCase (Context& context, const char* name, const char* desc) 1256 : ProgramBinaryCase (context, name, desc) 1257 , m_rnd (deStringHash(name) ^ 0xf2b48c6a) 1258 { 1259 } 1260 1261 virtual ~ProgramBinaryUniformResetCase (void) 1262 { 1263 } 1264 1265 std::string getShaderSource (const glu::ShaderType shaderType) const 1266 { 1267 const char* vertSrc = 1268 "#version 300 es\n" 1269 "uniform bool u_boolVar;\n" 1270 "uniform highp int u_intVar;\n" 1271 "uniform highp float u_floatVar;\n\n" 1272 "in highp vec4 a_position;\n\n" 1273 "void main (void)\n" 1274 "{\n" 1275 " gl_Position = a_position;\n" 1276 "}\n"; 1277 const char* fragSrc = 1278 "#version 300 es\n" 1279 "uniform bool u_boolVar;\n" 1280 "uniform highp int u_intVar;\n" 1281 "uniform highp float u_floatVar;\n\n" 1282 "layout(location = 0) out mediump vec4 o_fragColor;\n\n" 1283 "void main (void)\n" 1284 "{\n" 1285 " mediump float refAll = float(u_boolVar) + float(u_intVar) + u_floatVar;\n" 1286 " o_fragColor = vec4(refAll);\n" 1287 "}\n"; 1288 1289 DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT); 1290 1291 return (shaderType == glu::SHADERTYPE_VERTEX) ? vertSrc : fragSrc; 1292 } 1293 1294 void setUniformsRandom (glu::ShaderProgram& program) 1295 { 1296 TestLog& log = m_testCtx.getLog(); 1297 const deUint32 glProg = program.getProgram(); 1298 1299 log << TestLog::Message << "Setting uniforms to random non-zero values." << TestLog::EndMessage; 1300 1301 glUseProgram(glProg); 1302 1303 { 1304 const GLint boolLoc = glGetUniformLocation(glProg, "u_boolVar"); 1305 const GLint intLoc = glGetUniformLocation(glProg, "u_intVar"); 1306 const GLint floatLoc = glGetUniformLocation(glProg, "u_floatVar"); 1307 1308 const deInt32 intVal = m_rnd.getInt(1, 1000); 1309 const float floatVal = m_rnd.getFloat(1.0, 1000.0); 1310 1311 glUniform1i(boolLoc, GL_TRUE); 1312 glUniform1f(floatLoc, floatVal); 1313 glUniform1i(intLoc, intVal); 1314 } 1315 } 1316 1317 void verifyUniformInt (glu::ShaderProgram& program, const std::string& name) 1318 { 1319 const GLint intLoc = glGetUniformLocation(program.getProgram(), name.c_str()); 1320 GLint intVar = -1; 1321 1322 glGetUniformiv(program.getProgram(), intLoc, &intVar); 1323 1324 if (intVar != 0) 1325 { 1326 m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name << ", received: " << intVar << TestLog::EndMessage; 1327 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset"); 1328 } 1329 } 1330 1331 void verifyUniformFloat (glu::ShaderProgram& program, const std::string& name) 1332 { 1333 const GLint floatLoc = glGetUniformLocation(program.getProgram(), name.c_str()); 1334 GLfloat floatVar = -1; 1335 1336 glGetUniformfv(program.getProgram(), floatLoc, &floatVar); 1337 1338 if (floatVar != 0.0f) 1339 { 1340 m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name << ", received: " << de::toString(floatVar) << TestLog::EndMessage; 1341 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset"); 1342 } 1343 } 1344 1345 void verifyUniformsReset (glu::ShaderProgram& program) 1346 { 1347 m_testCtx.getLog() << TestLog::Message << "Verifying uniform reset to 0/false." << TestLog::EndMessage; 1348 1349 verifyUniformInt (program, "u_boolVar"); 1350 verifyUniformInt (program, "u_intVar"); 1351 verifyUniformFloat (program, "u_floatVar"); 1352 } 1353 1354 void test (void) 1355 { 1356 TestLog& log = m_testCtx.getLog(); 1357 1358 const std::string vertSrc = getShaderSource(glu::SHADERTYPE_VERTEX); 1359 const std::string fragSrc = getShaderSource(glu::SHADERTYPE_FRAGMENT); 1360 1361 const glu::ProgramSources sources = glu::makeVtxFragSources(vertSrc, fragSrc); 1362 1363 glu::ShaderProgram program (m_context.getRenderContext(), sources); 1364 1365 log << program; 1366 1367 TCU_CHECK_MSG(program.isOk(), "Couldn't build program"); 1368 1369 { 1370 ProgramBinary binary; 1371 1372 getProgramBinary(binary, program.getProgram()); 1373 verifyProgramBinary(binary); 1374 1375 setUniformsRandom(program); 1376 1377 log << TestLog::Message << "Rendering test image and reloading binary" << TestLog::EndMessage; 1378 1379 drawWithProgram(m_context.getRenderContext(), program.getProgram()); 1380 loadProgramBinary(binary, program.getProgram()); 1381 1382 verifyUniformsReset(program); 1383 } 1384 } 1385 private: 1386 de::Random m_rnd; 1387 }; 1388 1389 // Base class for program state persistence cases 1390 1391 class ProgramBinaryPersistenceCase : public ProgramBinaryCase 1392 { 1393 public: 1394 ProgramBinaryPersistenceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType); 1395 virtual ~ProgramBinaryPersistenceCase (void) {} 1396 1397 void buildProgram (glu::Program& program, ShaderAllocator& shaders); 1398 1399 void test (void); 1400 1401 virtual void executeForProgram (glu::Program& program, ShaderAllocator& shaders) = 0; 1402 virtual void verify (glu::Program& program, const ProgramBinary& binary); 1403 1404 protected: 1405 de::Random m_rnd; 1406 const glu::ShaderType m_shaderType; 1407 }; 1408 1409 ProgramBinaryPersistenceCase::ProgramBinaryPersistenceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1410 : ProgramBinaryCase (context, name, desc) 1411 , m_rnd (deStringHash(name) ^ 0x713de0ca) 1412 , m_shaderType (shaderType) 1413 { 1414 DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT); 1415 } 1416 1417 void ProgramBinaryPersistenceCase::buildProgram (glu::Program& program, ShaderAllocator& shaders) 1418 { 1419 TestLog& log = m_testCtx.getLog(); 1420 1421 glu::Shader& vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX); 1422 glu::Shader& fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT); 1423 1424 vertShader.compile(); 1425 fragShader.compile(); 1426 1427 program.attachShader(vertShader.getShader()); 1428 program.attachShader(fragShader.getShader()); 1429 program.link(); 1430 1431 logProgram(log, m_context.getRenderContext(), program, shaders); 1432 } 1433 1434 void ProgramBinaryPersistenceCase::verify (glu::Program& program, const ProgramBinary& binary) 1435 { 1436 TestLog& log = m_testCtx.getLog(); 1437 ProgramBinary currentBinary; 1438 1439 getProgramBinary(currentBinary, program.getProgram()); 1440 1441 if (!programBinariesEqual(binary, currentBinary)) 1442 { 1443 log << TestLog::Message << "Fail, program binary may only change as a result of linking or loading." << TestLog::EndMessage; 1444 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program binary changed"); 1445 } 1446 } 1447 1448 void ProgramBinaryPersistenceCase::test (void) 1449 { 1450 TestLog& log = m_testCtx.getLog(); 1451 glu::RenderContext& renderCtx = m_context.getRenderContext(); 1452 1453 ConstantShaderGenerator sourceGen (m_rnd); 1454 1455 ShaderAllocator shaders (renderCtx, sourceGen); 1456 glu::Program program (renderCtx); 1457 1458 buildProgram(program, shaders); 1459 1460 if (program.getLinkStatus()) 1461 { 1462 ProgramBinary binary; 1463 getProgramBinary(binary, program.getProgram()); 1464 1465 executeForProgram(program, shaders); 1466 1467 verify(program, binary); 1468 1469 logProgram(log, renderCtx, program, shaders); 1470 } 1471 else 1472 { 1473 log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage; 1474 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed"); 1475 } 1476 } 1477 1478 // Program state case utilities 1479 1480 namespace 1481 { 1482 1483 template<class T> 1484 void addProgramBinaryPersistenceCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc) 1485 { 1486 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 1487 { 1488 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 1489 const std::string shaderTypeName = getShaderTypeName(shaderType); 1490 1491 const std::string caseName = name + "_" + shaderTypeName; 1492 const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader."; 1493 1494 group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType)); 1495 } 1496 } 1497 1498 } // anonymous 1499 1500 // Specialized program state cases 1501 1502 class ProgramBinaryPersistenceDetachShaderCase : public ProgramBinaryPersistenceCase 1503 { 1504 public: 1505 ProgramBinaryPersistenceDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1506 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1507 { 1508 } 1509 1510 virtual ~ProgramBinaryPersistenceDetachShaderCase (void) 1511 { 1512 } 1513 1514 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1515 { 1516 TestLog& log = m_testCtx.getLog(); 1517 glu::Shader& caseShader = shaders.get(m_shaderType); 1518 1519 log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1520 program.detachShader(caseShader.getShader()); 1521 } 1522 }; 1523 1524 class ProgramBinaryPersistenceReattachShaderCase : public ProgramBinaryPersistenceCase 1525 { 1526 public: 1527 ProgramBinaryPersistenceReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1528 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1529 { 1530 } 1531 1532 virtual ~ProgramBinaryPersistenceReattachShaderCase (void) 1533 { 1534 } 1535 1536 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1537 { 1538 TestLog& log = m_testCtx.getLog(); 1539 glu::Shader& caseShader = shaders.get(m_shaderType); 1540 1541 log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1542 program.detachShader(caseShader.getShader()); 1543 program.attachShader(caseShader.getShader()); 1544 } 1545 }; 1546 1547 class ProgramBinaryPersistenceDeleteShaderCase : public ProgramBinaryPersistenceCase 1548 { 1549 public: 1550 ProgramBinaryPersistenceDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1551 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1552 { 1553 } 1554 1555 virtual ~ProgramBinaryPersistenceDeleteShaderCase (void) 1556 { 1557 } 1558 1559 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1560 { 1561 TestLog& log = m_testCtx.getLog(); 1562 glu::Shader& caseShader = shaders.get(m_shaderType); 1563 1564 log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1565 program.detachShader(caseShader.getShader()); 1566 shaders.deleteShader(m_shaderType); 1567 } 1568 }; 1569 1570 class ProgramBinaryPersistenceReplaceShaderCase : public ProgramBinaryPersistenceCase 1571 { 1572 public: 1573 ProgramBinaryPersistenceReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1574 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1575 { 1576 } 1577 1578 virtual ~ProgramBinaryPersistenceReplaceShaderCase (void) 1579 { 1580 } 1581 1582 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1583 { 1584 TestLog& log = m_testCtx.getLog(); 1585 glu::Shader& caseShader = shaders.get(m_shaderType); 1586 1587 log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1588 program.detachShader(caseShader.getShader()); 1589 shaders.deleteShader(m_shaderType); 1590 program.attachShader(shaders.createShader(m_shaderType).getShader()); 1591 } 1592 }; 1593 1594 class ProgramBinaryPersistenceRecompileShaderCase : public ProgramBinaryPersistenceCase 1595 { 1596 public: 1597 ProgramBinaryPersistenceRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1598 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1599 { 1600 } 1601 1602 virtual ~ProgramBinaryPersistenceRecompileShaderCase (void) 1603 { 1604 } 1605 1606 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1607 { 1608 TestLog& log = m_testCtx.getLog(); 1609 glu::Shader& caseShader = shaders.get(m_shaderType); 1610 1611 log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 1612 caseShader.compile(); 1613 DE_UNREF(program); 1614 } 1615 }; 1616 1617 class ProgramBinaryPersistenceReplaceSourceCase : public ProgramBinaryPersistenceCase 1618 { 1619 public: 1620 ProgramBinaryPersistenceReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 1621 : ProgramBinaryPersistenceCase (context, name, desc, shaderType) 1622 { 1623 } 1624 1625 virtual ~ProgramBinaryPersistenceReplaceSourceCase (void) 1626 { 1627 } 1628 1629 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1630 { 1631 TestLog& log = m_testCtx.getLog(); 1632 glu::Shader& caseShader = shaders.get(m_shaderType); 1633 1634 log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage; 1635 shaders.setSource(m_shaderType); 1636 caseShader.compile(); 1637 DE_UNREF(program); 1638 } 1639 }; 1640 1641 // Test group 1642 1643 ShaderApiTests::ShaderApiTests (Context& context) 1644 : TestCaseGroup(context, "shader_api", "Shader API Cases") 1645 { 1646 } 1647 1648 ShaderApiTests::~ShaderApiTests (void) 1649 { 1650 } 1651 1652 void ShaderApiTests::init (void) 1653 { 1654 // create and delete shaders 1655 { 1656 TestCaseGroup* createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests"); 1657 addChild(createDeleteGroup); 1658 1659 createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_vertex_shader", "Create vertex shader object", glu::SHADERTYPE_VERTEX)); 1660 createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_fragment_shader", "Create fragment shader object", glu::SHADERTYPE_FRAGMENT)); 1661 1662 createDeleteGroup->addChild(new DeleteShaderCase(m_context, "delete_vertex_fragment", "Delete vertex shader and fragment shader")); 1663 } 1664 1665 // compile and link 1666 { 1667 TestCaseGroup* compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests"); 1668 addChild(compileLinkGroup); 1669 1670 compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_vertex_shader", "Compile vertex shader", glu::SHADERTYPE_VERTEX)); 1671 compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_fragment_shader", "Compile fragment shader", glu::SHADERTYPE_FRAGMENT)); 1672 1673 compileLinkGroup->addChild(new LinkVertexFragmentCase(m_context, "link_vertex_fragment", "Link vertex and fragment shaders")); 1674 } 1675 1676 // shader source 1677 { 1678 TestCaseGroup* shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests"); 1679 addChild(shaderSourceGroup); 1680 1681 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 1682 { 1683 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 1684 const std::string shaderTypeName = getShaderTypeName(shaderType); 1685 1686 const std::string caseName = std::string("replace_source_") + shaderTypeName; 1687 const std::string caseDesc = std::string("Replace source code of ") + shaderTypeName + " shader."; 1688 1689 shaderSourceGroup->addChild(new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType)); 1690 } 1691 1692 for (int stringLengthsInt = 0; stringLengthsInt < 3; stringLengthsInt++) 1693 for (int caseNdx = 1; caseNdx <= 3; caseNdx++) 1694 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 1695 { 1696 const int numSlices = 1 << caseNdx; 1697 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 1698 1699 const bool explicitLengths = (stringLengthsInt != 0); 1700 const bool randomNullTerm = (stringLengthsInt == 2); 1701 1702 const deUint32 flags = (explicitLengths ? CASE_EXPLICIT_SOURCE_LENGTHS : 0) 1703 | (randomNullTerm ? CASE_RANDOM_NULL_TERMINATED : 0); 1704 1705 const std::string caseName = "split_source_" 1706 + de::toString(numSlices) 1707 + (randomNullTerm ? "_random_negative_length" : (explicitLengths ? "_specify_lengths" : "_null_terminated")) 1708 + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex"); 1709 1710 const std::string caseDesc = std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex") 1711 + " shader source split into " 1712 + de::toString(numSlices) 1713 + " pieces" 1714 + (explicitLengths ? ", using explicitly specified string lengths" : "") 1715 + (randomNullTerm ? " with random negative length values" : ""); 1716 1717 shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType, numSlices, flags)); 1718 } 1719 } 1720 1721 // link status and infolog 1722 { 1723 TestCaseGroup* linkStatusGroup = new TestCaseGroup(m_context, "program_state", "Program state persistence tests"); 1724 addChild(linkStatusGroup); 1725 1726 addProgramStateCase<ProgramStateDetachShaderCase> (linkStatusGroup, m_context, "detach_shader", "detach shader"); 1727 addProgramStateCase<ProgramStateReattachShaderCase> (linkStatusGroup, m_context, "reattach_shader", "reattach shader"); 1728 addProgramStateCase<ProgramStateDeleteShaderCase> (linkStatusGroup, m_context, "delete_shader", "delete shader"); 1729 addProgramStateCase<ProgramStateReplaceShaderCase> (linkStatusGroup, m_context, "replace_shader", "replace shader object"); 1730 addProgramStateCase<ProgramStateRecompileShaderCase> (linkStatusGroup, m_context, "recompile_shader", "recompile shader"); 1731 addProgramStateCase<ProgramStateReplaceSourceCase> (linkStatusGroup, m_context, "replace_source", "replace shader source"); 1732 } 1733 1734 // program binary 1735 { 1736 TestCaseGroup* programBinaryGroup = new TestCaseGroup(m_context, "program_binary", "Program binary API tests"); 1737 addChild(programBinaryGroup); 1738 1739 { 1740 TestCaseGroup* simpleCaseGroup = new TestCaseGroup(m_context, "simple", "Simple API tests"); 1741 programBinaryGroup->addChild(simpleCaseGroup); 1742 1743 simpleCaseGroup->addChild(new ProgramBinarySimpleCase (m_context, "get_program_binary_vertex_fragment", "Get vertex and fragment shader program binary")); 1744 simpleCaseGroup->addChild(new ProgramBinaryUniformResetCase (m_context, "uniform_reset_on_binary_load", "Verify uniform reset on successful load of program binary")); 1745 } 1746 1747 { 1748 TestCaseGroup* binaryPersistenceGroup = new TestCaseGroup(m_context, "binary_persistence", "Program binary persistence tests"); 1749 programBinaryGroup->addChild(binaryPersistenceGroup); 1750 1751 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDetachShaderCase> (binaryPersistenceGroup, m_context, "detach_shader", "detach shader"); 1752 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReattachShaderCase> (binaryPersistenceGroup, m_context, "reattach_shader", "reattach shader"); 1753 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDeleteShaderCase> (binaryPersistenceGroup, m_context, "delete_shader", "delete shader"); 1754 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceShaderCase> (binaryPersistenceGroup, m_context, "replace_shader", "replace shader object"); 1755 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceRecompileShaderCase> (binaryPersistenceGroup, m_context, "recompile_shader", "recompile shader"); 1756 addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceSourceCase> (binaryPersistenceGroup, m_context, "replace_source", "replace shader source"); 1757 } 1758 } 1759 } 1760 1761 } // Functional 1762 } // gles3 1763 } // deqp 1764