1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.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 "es2fShaderApiTests.hpp" 25 #include "es2fApiCase.hpp" 26 #include "tcuTestLog.hpp" 27 28 #include "gluRenderContext.hpp" 29 #include "gluShaderProgram.hpp" 30 #include "gluContextInfo.hpp" 31 #include "glwFunctions.hpp" 32 #include "glwDefs.hpp" 33 #include "glwEnums.hpp" 34 35 #include "deString.h" 36 37 #include "deRandom.hpp" 38 #include "deStringUtil.hpp" 39 40 #include <string> 41 #include <vector> 42 #include <map> 43 44 using namespace glw; // GL types 45 46 namespace deqp 47 { 48 namespace gles2 49 { 50 namespace Functional 51 { 52 53 using tcu::TestLog; 54 55 namespace 56 { 57 58 enum ShaderSourceCaseFlags 59 { 60 CASE_EXPLICIT_SOURCE_LENGTHS = 1, 61 CASE_RANDOM_NULL_TERMINATED = 2 62 }; 63 64 struct ShaderSources 65 { 66 std::vector<std::string> strings; 67 std::vector<int> lengths; 68 }; 69 70 // Simple shaders 71 72 const char* getSimpleShaderSource (const glu::ShaderType shaderType) 73 { 74 const char* simpleVertexShaderSource = "void main (void) { gl_Position = vec4(0.0); }\n"; 75 const char* simpleFragmentShaderSource = "void main (void) { gl_FragColor = vec4(0.0); }\n"; 76 77 switch (shaderType) 78 { 79 case glu::SHADERTYPE_VERTEX: 80 return simpleVertexShaderSource; 81 case glu::SHADERTYPE_FRAGMENT: 82 return simpleFragmentShaderSource; 83 default: 84 DE_ASSERT(DE_FALSE); 85 } 86 87 return 0; 88 } 89 90 void setShaderSources (glu::Shader& shader, const ShaderSources& sources) 91 { 92 std::vector<const char*> cStrings (sources.strings.size(), 0); 93 94 for (size_t ndx = 0; ndx < sources.strings.size(); ndx++) 95 cStrings[ndx] = sources.strings[ndx].c_str(); 96 97 if (sources.lengths.size() > 0) 98 shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]); 99 else 100 shader.setSources((int)cStrings.size(), &cStrings[0], 0); 101 } 102 103 void sliceSourceString (const std::string& in, ShaderSources& out, const int numSlices, const size_t paddingLength = 0) 104 { 105 DE_ASSERT(numSlices > 0); 106 107 const size_t sliceSize = in.length() / numSlices; 108 const size_t sliceSizeRemainder = in.length() - (sliceSize * numSlices); 109 const std::string padding (paddingLength, 'E'); 110 111 for (int i = 0; i < numSlices; i++) 112 { 113 out.strings.push_back(in.substr(i * sliceSize, sliceSize) + padding); 114 115 if (paddingLength > 0) 116 out.lengths.push_back((int)sliceSize); 117 } 118 119 if (sliceSizeRemainder > 0) 120 { 121 const std::string lastString = in.substr(numSlices * sliceSize); 122 const int lastStringLength = (int)lastString.length(); 123 124 out.strings.push_back(lastString + padding); 125 126 if (paddingLength > 0) 127 out.lengths.push_back(lastStringLength); 128 } 129 } 130 131 void queryShaderInfo (glu::RenderContext& renderCtx, deUint32 shader, glu::ShaderInfo& info) 132 { 133 const glw::Functions& gl = renderCtx.getFunctions(); 134 135 info.compileOk = false; 136 info.compileTimeUs = 0; 137 info.infoLog.clear(); 138 139 // Query source, status & log. 140 { 141 int compileStatus = 0; 142 int sourceLen = 0; 143 int infoLogLen = 0; 144 int unusedLen; 145 146 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); 147 gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen); 148 gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen); 149 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()"); 150 151 info.compileOk = compileStatus != GL_FALSE; 152 153 if (sourceLen > 0) 154 { 155 std::vector<char> source(sourceLen); 156 gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]); 157 info.source = std::string(&source[0], sourceLen); 158 } 159 160 if (infoLogLen > 0) 161 { 162 std::vector<char> infoLog(infoLogLen); 163 gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]); 164 info.infoLog = std::string(&infoLog[0], infoLogLen); 165 } 166 } 167 } 168 169 // Shader source generator 170 171 class SourceGenerator 172 { 173 public: 174 virtual ~SourceGenerator (void) {} 175 176 virtual std::string next (const glu::ShaderType shaderType) = 0; 177 virtual bool finished (const glu::ShaderType shaderType) const = 0; 178 }; 179 180 class ConstantShaderGenerator : public SourceGenerator 181 { 182 public: 183 ConstantShaderGenerator (de::Random& rnd) : m_rnd(rnd) {} 184 ~ConstantShaderGenerator (void) {} 185 186 bool finished (const glu::ShaderType shaderType) const { DE_UNREF(shaderType); return false; } 187 188 std::string next (const glu::ShaderType shaderType); 189 190 private: 191 de::Random m_rnd; 192 }; 193 194 std::string ConstantShaderGenerator::next (const glu::ShaderType shaderType) 195 { 196 DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT); 197 198 const float value = m_rnd.getFloat(0.0f, 1.0f); 199 const std::string valueString = de::toString(value); 200 const std::string outputName = (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "gl_FragColor"; 201 202 std::string source = 203 "#version 100\n" 204 "void main (void) { " + outputName + " = vec4(" + valueString + "); }\n"; 205 206 return source; 207 } 208 209 // Shader allocation utility 210 211 class ShaderAllocator 212 { 213 public: 214 ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator); 215 ~ShaderAllocator (void); 216 217 bool hasShader (const glu::ShaderType shaderType); 218 219 void setSource (const glu::ShaderType shaderType); 220 221 glu::Shader& createShader (const glu::ShaderType shaderType); 222 void deleteShader (const glu::ShaderType shaderType); 223 224 glu::Shader& get (const glu::ShaderType shaderType) { DE_ASSERT(hasShader(shaderType)); return *m_shaders[shaderType]; } 225 226 private: 227 const glu::RenderContext& m_context; 228 SourceGenerator& m_srcGen; 229 std::map<glu::ShaderType, glu::Shader*> m_shaders; 230 }; 231 232 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator) 233 : m_context (context) 234 , m_srcGen (generator) 235 { 236 } 237 238 ShaderAllocator::~ShaderAllocator (void) 239 { 240 for (std::map<glu::ShaderType, glu::Shader*>::iterator shaderIter = m_shaders.begin(); shaderIter != m_shaders.end(); shaderIter++) 241 delete shaderIter->second; 242 m_shaders.clear(); 243 } 244 245 bool ShaderAllocator::hasShader (const glu::ShaderType shaderType) 246 { 247 if (m_shaders.find(shaderType) != m_shaders.end()) 248 return true; 249 else 250 return false; 251 } 252 253 glu::Shader& ShaderAllocator::createShader (const glu::ShaderType shaderType) 254 { 255 DE_ASSERT(!this->hasShader(shaderType)); 256 257 glu::Shader* const shader = new glu::Shader(m_context, shaderType); 258 259 m_shaders[shaderType] = shader; 260 this->setSource(shaderType); 261 262 return *shader; 263 } 264 265 void ShaderAllocator::deleteShader (const glu::ShaderType shaderType) 266 { 267 DE_ASSERT(this->hasShader(shaderType)); 268 269 delete m_shaders[shaderType]; 270 m_shaders.erase(shaderType); 271 } 272 273 void ShaderAllocator::setSource (const glu::ShaderType shaderType) 274 { 275 DE_ASSERT(this->hasShader(shaderType)); 276 DE_ASSERT(!m_srcGen.finished(shaderType)); 277 278 const std::string source = m_srcGen.next(shaderType); 279 const char* const cSource = source.c_str(); 280 281 m_shaders[shaderType]->setSources(1, &cSource, 0); 282 } 283 284 // Logging utilities 285 286 void logShader (TestLog& log, glu::RenderContext& renderCtx, glu::Shader& shader) 287 { 288 glu::ShaderInfo info; 289 queryShaderInfo(renderCtx, shader.getShader(), info); 290 291 log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog); 292 } 293 294 void logProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, ShaderAllocator& shaders) 295 { 296 log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog()); 297 298 for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++) 299 { 300 const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt; 301 302 if (shaders.hasShader(shaderType)) 303 logShader(log, renderCtx, shaders.get(shaderType)); 304 } 305 306 log << TestLog::EndShaderProgram; 307 } 308 309 void logVertexFragmentProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, glu::Shader& vertShader, glu::Shader& fragShader) 310 { 311 DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT); 312 313 log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog()); 314 315 logShader(log, renderCtx, vertShader); 316 logShader(log, renderCtx, fragShader); 317 318 log << TestLog::EndShaderProgram; 319 } 320 321 } // anonymous 322 323 // Simple glCreateShader() case 324 325 class CreateShaderCase : public ApiCase 326 { 327 public: 328 CreateShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 329 : ApiCase (context, name, desc) 330 , m_shaderType (shaderType) 331 { 332 } 333 334 void test (void) 335 { 336 const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType)); 337 338 TCU_CHECK(shaderObject != 0); 339 340 glDeleteShader(shaderObject); 341 } 342 343 private: 344 const glu::ShaderType m_shaderType; 345 }; 346 347 // Simple glCompileShader() case 348 349 class CompileShaderCase : public ApiCase 350 { 351 public: 352 CompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 353 : ApiCase (context, name, desc) 354 , m_shaderType (shaderType) 355 { 356 } 357 358 bool checkCompileStatus (const GLuint shaderObject) 359 { 360 GLint compileStatus = -1; 361 glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus); 362 GLU_CHECK(); 363 364 return (compileStatus == GL_TRUE); 365 } 366 367 void test (void) 368 { 369 const char* shaderSource = getSimpleShaderSource(m_shaderType); 370 const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType)); 371 372 TCU_CHECK(shaderObject != 0); 373 374 glShaderSource(shaderObject, 1, &shaderSource, 0); 375 glCompileShader(shaderObject); 376 377 TCU_CHECK(checkCompileStatus(shaderObject)); 378 379 glDeleteShader(shaderObject); 380 } 381 382 private: 383 const glu::ShaderType m_shaderType; 384 }; 385 386 // Base class for simple program API tests 387 388 class SimpleProgramCase : public ApiCase 389 { 390 public: 391 SimpleProgramCase (Context& context, const char* name, const char* desc) 392 : ApiCase (context, name, desc) 393 , m_vertShader (0) 394 , m_fragShader (0) 395 , m_program (0) 396 { 397 } 398 399 virtual ~SimpleProgramCase (void) 400 { 401 } 402 403 virtual void compileShaders (void) 404 { 405 const char* vertSource = getSimpleShaderSource(glu::SHADERTYPE_VERTEX); 406 const char* fragSource = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT); 407 408 const GLuint vertShader = glCreateShader(GL_VERTEX_SHADER); 409 const GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); 410 411 TCU_CHECK(vertShader != 0); 412 TCU_CHECK(fragShader != 0); 413 414 glShaderSource(vertShader, 1, &vertSource, 0); 415 glCompileShader(vertShader); 416 417 glShaderSource(fragShader, 1, &fragSource, 0); 418 glCompileShader(fragShader); 419 420 GLU_CHECK(); 421 422 m_vertShader = vertShader; 423 m_fragShader = fragShader; 424 } 425 426 void linkProgram (void) 427 { 428 const GLuint program = glCreateProgram(); 429 430 TCU_CHECK(program != 0); 431 432 glAttachShader(program, m_vertShader); 433 glAttachShader(program, m_fragShader); 434 GLU_CHECK(); 435 436 glLinkProgram(program); 437 438 m_program = program; 439 } 440 441 void cleanup (void) 442 { 443 glDeleteShader(m_vertShader); 444 glDeleteShader(m_fragShader); 445 glDeleteProgram(m_program); 446 } 447 448 protected: 449 GLuint m_vertShader; 450 GLuint m_fragShader; 451 GLuint m_program; 452 }; 453 454 // glDeleteShader() case 455 456 class DeleteShaderCase : public SimpleProgramCase 457 { 458 public: 459 DeleteShaderCase (Context& context, const char* name, const char* desc) 460 : SimpleProgramCase (context, name, desc) 461 { 462 } 463 464 bool checkDeleteStatus(GLuint shader) 465 { 466 GLint deleteStatus = -1; 467 glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus); 468 GLU_CHECK(); 469 470 return (deleteStatus == GL_TRUE); 471 } 472 473 void deleteShaders (void) 474 { 475 glDeleteShader(m_vertShader); 476 glDeleteShader(m_fragShader); 477 GLU_CHECK(); 478 } 479 480 void test (void) 481 { 482 compileShaders(); 483 linkProgram(); 484 GLU_CHECK(); 485 486 deleteShaders(); 487 488 TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader)); 489 490 glDeleteProgram(m_program); 491 492 TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader))); 493 } 494 }; 495 496 // Simple glLinkProgram() case 497 498 class LinkVertexFragmentCase : public SimpleProgramCase 499 { 500 public: 501 LinkVertexFragmentCase (Context& context, const char* name, const char* desc) 502 : SimpleProgramCase (context, name, desc) 503 { 504 } 505 506 bool checkLinkStatus (const GLuint programObject) 507 { 508 GLint linkStatus = -1; 509 glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus); 510 GLU_CHECK(); 511 512 return (linkStatus == GL_TRUE); 513 } 514 515 void test (void) 516 { 517 compileShaders(); 518 linkProgram(); 519 520 GLU_CHECK_MSG("Linking failed."); 521 TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE."); 522 523 cleanup(); 524 } 525 }; 526 527 class ShaderSourceReplaceCase : public ApiCase 528 { 529 public: 530 ShaderSourceReplaceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 531 : ApiCase (context, name, desc) 532 , m_shaderType (shaderType) 533 { 534 } 535 536 std::string generateFirstSource (void) 537 { 538 return getSimpleShaderSource(m_shaderType); 539 } 540 541 std::string generateSecondSource (void) 542 { 543 std::string str; 544 545 str = "#version 100\n"; 546 str += "precision highp float;\n\n"; 547 548 str += "void main()\n"; 549 str += "{\n"; 550 str += " float variable = 1.0;\n"; 551 552 if (m_shaderType == glu::SHADERTYPE_VERTEX) str += " gl_Position = vec4(variable);\n"; 553 else if (m_shaderType == glu::SHADERTYPE_FRAGMENT) str += " gl_FragColor = vec4(variable);\n"; 554 555 str += "}\n"; 556 557 return str; 558 } 559 560 GLint getSourceLength (glu::Shader& shader) 561 { 562 GLint sourceLength = 0; 563 glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength); 564 GLU_CHECK(); 565 566 return sourceLength; 567 } 568 569 std::string readSource (glu::Shader& shader) 570 { 571 const GLint sourceLength = getSourceLength(shader); 572 std::vector<char> sourceBuffer (sourceLength + 1); 573 574 glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]); 575 576 return std::string(&sourceBuffer[0]); 577 } 578 579 void verifyShaderSourceReplaced (glu::Shader& shader, const std::string& firstSource, const std::string& secondSource) 580 { 581 TestLog& log = m_testCtx.getLog(); 582 const std::string result = readSource(shader); 583 584 if (result == firstSource) 585 { 586 log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage; 587 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced"); 588 } 589 else if (result != secondSource) 590 { 591 log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage; 592 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source"); 593 } 594 } 595 596 void test (void) 597 { 598 TestLog& log = m_testCtx.getLog(); 599 600 glu::Shader shader (m_context.getRenderContext(), m_shaderType); 601 602 const std::string firstSourceStr = generateFirstSource(); 603 const std::string secondSourceStr = generateSecondSource(); 604 605 const char* firstSource = firstSourceStr.c_str(); 606 const char* secondSource = secondSourceStr.c_str(); 607 608 log << TestLog::Message << "Setting shader source." << TestLog::EndMessage; 609 610 shader.setSources(1, &firstSource, 0); 611 GLU_CHECK(); 612 613 log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage; 614 615 shader.setSources(1, &secondSource, 0); 616 GLU_CHECK(); 617 618 verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr); 619 } 620 621 private: 622 glu::ShaderType m_shaderType; 623 }; 624 625 // glShaderSource() split source case 626 627 class ShaderSourceSplitCase : public ApiCase 628 { 629 public: 630 ShaderSourceSplitCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType, const int numSlices, const deUint32 flags = 0) 631 : ApiCase (context, name, desc) 632 , m_rnd (deStringHash(getName()) ^ 0x4fb2337d) 633 , m_shaderType (shaderType) 634 , m_numSlices (numSlices) 635 , m_explicitLengths ((flags & CASE_EXPLICIT_SOURCE_LENGTHS) != 0) 636 , m_randomNullTerm ((flags & CASE_RANDOM_NULL_TERMINATED) != 0) 637 { 638 DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT); 639 } 640 641 virtual ~ShaderSourceSplitCase (void) 642 { 643 } 644 645 std::string generateFullSource (void) 646 { 647 std::string str; 648 649 str = "#version 100\n"; 650 str += "precision highp float;\n\n"; 651 652 str += "void main()\n"; 653 str += "{\n"; 654 str += " float variable = 1.0;\n"; 655 656 if (m_shaderType == glu::SHADERTYPE_VERTEX) str += " gl_Position = vec4(variable);\n"; 657 else if (m_shaderType == glu::SHADERTYPE_FRAGMENT) str += " gl_FragColor = vec4(variable);\n"; 658 659 str += "}\n"; 660 661 return str; 662 } 663 664 void insertRandomNullTermStrings (ShaderSources& sources) 665 { 666 const int numInserts = de::max(m_numSlices >> 2, 1); 667 std::vector<int> indices (sources.strings.size(), 0); 668 669 DE_ASSERT(sources.lengths.size() > 0); 670 DE_ASSERT(sources.lengths.size() == sources.strings.size()); 671 672 for (int i = 0; i < (int)sources.strings.size(); i++) 673 indices[i] = i; 674 675 m_rnd.shuffle(indices.begin(), indices.end()); 676 677 for (int i = 0; i < numInserts; i++) 678 { 679 const int ndx = indices[i]; 680 const int unpaddedLength = sources.lengths[ndx]; 681 const std::string unpaddedString = sources.strings[ndx].substr(0, unpaddedLength); 682 683 sources.strings[ndx] = unpaddedString; 684 sources.lengths[ndx] = m_rnd.getInt(-10, -1); 685 } 686 } 687 688 void generateSources (ShaderSources& sources) 689 { 690 const size_t paddingLength = (m_explicitLengths ? 10 : 0); 691 std::string str = generateFullSource(); 692 693 sliceSourceString(str, sources, m_numSlices, paddingLength); 694 695 if (m_randomNullTerm) 696 insertRandomNullTermStrings(sources); 697 } 698 699 void buildProgram (glu::Shader& shader) 700 { 701 TestLog& log = m_testCtx.getLog(); 702 glu::RenderContext& renderCtx = m_context.getRenderContext(); 703 704 const glu::ShaderType supportShaderType = (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT); 705 const char* supportShaderSource = getSimpleShaderSource(supportShaderType); 706 glu::Shader supportShader (renderCtx, supportShaderType); 707 708 glu::Program program (renderCtx); 709 710 supportShader.setSources(1, &supportShaderSource, 0); 711 supportShader.compile(); 712 713 program.attachShader(shader.getShader()); 714 program.attachShader(supportShader.getShader()); 715 716 program.link(); 717 718 if (m_shaderType == glu::SHADERTYPE_VERTEX) 719 logVertexFragmentProgram(log, renderCtx, program, shader, supportShader); 720 else 721 logVertexFragmentProgram(log, renderCtx, program, supportShader, shader); 722 } 723 724 void test (void) 725 { 726 TestLog& log = m_testCtx.getLog(); 727 glu::RenderContext& renderCtx = m_context.getRenderContext(); 728 729 ShaderSources sources; 730 glu::Shader shader (renderCtx, m_shaderType); 731 732 generateSources(sources); 733 setShaderSources(shader, sources); 734 shader.compile(); 735 736 buildProgram(shader); 737 738 if (!shader.getCompileStatus()) 739 { 740 log << TestLog::Message << "Compilation failed." << TestLog::EndMessage; 741 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 742 } 743 } 744 745 private: 746 de::Random m_rnd; 747 748 glu::ShaderType m_shaderType; 749 const int m_numSlices; 750 751 const bool m_explicitLengths; 752 const bool m_randomNullTerm; 753 }; 754 755 // Base class for program state persistence cases 756 757 class ProgramStateCase : public ApiCase 758 { 759 public: 760 ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType); 761 virtual ~ProgramStateCase (void) {} 762 763 void buildProgram (glu::Program& program, ShaderAllocator& shaders); 764 void verify (glu::Program& program, const glu::ProgramInfo& reference); 765 766 void test (void); 767 768 virtual void executeForProgram (glu::Program& program, ShaderAllocator& shaders) = 0; 769 770 protected: 771 de::Random m_rnd; 772 const glu::ShaderType m_shaderType; 773 }; 774 775 ProgramStateCase::ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 776 : ApiCase (context, name, desc) 777 , m_rnd (deStringHash(name) ^ 0x713de0ca) 778 , m_shaderType (shaderType) 779 { 780 DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT); 781 } 782 783 void ProgramStateCase::buildProgram (glu::Program& program, ShaderAllocator& shaders) 784 { 785 TestLog& log = m_testCtx.getLog(); 786 787 glu::Shader& vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX); 788 glu::Shader& fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT); 789 790 vertShader.compile(); 791 fragShader.compile(); 792 793 program.attachShader(vertShader.getShader()); 794 program.attachShader(fragShader.getShader()); 795 program.link(); 796 797 logProgram(log, m_context.getRenderContext(), program, shaders); 798 } 799 800 void ProgramStateCase::verify (glu::Program& program, const glu::ProgramInfo& reference) 801 { 802 TestLog& log = m_testCtx.getLog(); 803 const glu::ProgramInfo& programInfo = program.getInfo(); 804 805 if (!programInfo.linkOk) 806 { 807 log << TestLog::Message << "Fail, link status may only change as a result of linking or loading a program binary." << TestLog::EndMessage; 808 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed"); 809 } 810 811 if (programInfo.linkTimeUs != reference.linkTimeUs) 812 { 813 log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage; 814 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed"); 815 } 816 817 if (programInfo.infoLog != reference.infoLog) 818 { 819 log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage; 820 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed"); 821 } 822 } 823 824 void ProgramStateCase::test (void) 825 { 826 TestLog& log = m_testCtx.getLog(); 827 glu::RenderContext& renderCtx = m_context.getRenderContext(); 828 829 ConstantShaderGenerator sourceGen (m_rnd); 830 831 ShaderAllocator shaders (renderCtx, sourceGen); 832 glu::Program program (renderCtx); 833 834 buildProgram(program, shaders); 835 836 if (program.getLinkStatus()) 837 { 838 glu::ProgramInfo programInfo = program.getInfo(); 839 840 executeForProgram(program, shaders); 841 842 verify(program, programInfo); 843 844 logProgram(log, renderCtx, program, shaders); 845 } 846 else 847 { 848 log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage; 849 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed"); 850 } 851 } 852 853 // Program state case utilities 854 855 namespace 856 { 857 858 template<class T> 859 void addProgramStateCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc) 860 { 861 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 862 { 863 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 864 const std::string shaderTypeName = getShaderTypeName(shaderType); 865 866 const std::string caseName = name + "_" + shaderTypeName; 867 const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader."; 868 869 group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType)); 870 } 871 } 872 873 } // anonymous 874 875 // Specialized program state cases 876 877 class ProgramStateDetachShaderCase : public ProgramStateCase 878 { 879 public: 880 ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 881 : ProgramStateCase (context, name, desc, shaderType) 882 { 883 } 884 885 virtual ~ProgramStateDetachShaderCase (void) 886 { 887 } 888 889 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 890 { 891 TestLog& log = m_testCtx.getLog(); 892 glu::Shader& caseShader = shaders.get(m_shaderType); 893 894 log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 895 program.detachShader(caseShader.getShader()); 896 } 897 }; 898 899 class ProgramStateReattachShaderCase : public ProgramStateCase 900 { 901 public: 902 ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 903 : ProgramStateCase (context, name, desc, shaderType) 904 { 905 } 906 907 virtual ~ProgramStateReattachShaderCase (void) 908 { 909 } 910 911 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 912 { 913 TestLog& log = m_testCtx.getLog(); 914 glu::Shader& caseShader = shaders.get(m_shaderType); 915 916 log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 917 program.detachShader(caseShader.getShader()); 918 program.attachShader(caseShader.getShader()); 919 } 920 }; 921 922 class ProgramStateDeleteShaderCase : public ProgramStateCase 923 { 924 public: 925 ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 926 : ProgramStateCase (context, name, desc, shaderType) 927 { 928 } 929 930 virtual ~ProgramStateDeleteShaderCase (void) 931 { 932 } 933 934 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 935 { 936 TestLog& log = m_testCtx.getLog(); 937 glu::Shader& caseShader = shaders.get(m_shaderType); 938 939 log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 940 program.detachShader(caseShader.getShader()); 941 shaders.deleteShader(m_shaderType); 942 } 943 }; 944 945 class ProgramStateReplaceShaderCase : public ProgramStateCase 946 { 947 public: 948 ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 949 : ProgramStateCase (context, name, desc, shaderType) 950 { 951 } 952 953 virtual ~ProgramStateReplaceShaderCase (void) 954 { 955 } 956 957 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 958 { 959 TestLog& log = m_testCtx.getLog(); 960 glu::Shader& caseShader = shaders.get(m_shaderType); 961 962 log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 963 program.detachShader(caseShader.getShader()); 964 shaders.deleteShader(m_shaderType); 965 program.attachShader(shaders.createShader(m_shaderType).getShader()); 966 } 967 }; 968 969 class ProgramStateRecompileShaderCase : public ProgramStateCase 970 { 971 public: 972 ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 973 : ProgramStateCase (context, name, desc, shaderType) 974 { 975 } 976 977 virtual ~ProgramStateRecompileShaderCase (void) 978 { 979 } 980 981 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 982 { 983 TestLog& log = m_testCtx.getLog(); 984 glu::Shader& caseShader = shaders.get(m_shaderType); 985 986 log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage; 987 caseShader.compile(); 988 DE_UNREF(program); 989 } 990 }; 991 992 class ProgramStateReplaceSourceCase : public ProgramStateCase 993 { 994 public: 995 ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType) 996 : ProgramStateCase (context, name, desc, shaderType) 997 { 998 } 999 1000 virtual ~ProgramStateReplaceSourceCase (void) 1001 { 1002 } 1003 1004 void executeForProgram (glu::Program& program, ShaderAllocator& shaders) 1005 { 1006 TestLog& log = m_testCtx.getLog(); 1007 glu::Shader& caseShader = shaders.get(m_shaderType); 1008 1009 log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage; 1010 shaders.setSource(m_shaderType); 1011 caseShader.compile(); 1012 DE_UNREF(program); 1013 } 1014 }; 1015 1016 // Test group 1017 1018 ShaderApiTests::ShaderApiTests (Context& context) 1019 : TestCaseGroup(context, "shader_api", "Shader API Cases") 1020 { 1021 } 1022 1023 ShaderApiTests::~ShaderApiTests (void) 1024 { 1025 } 1026 1027 void ShaderApiTests::init (void) 1028 { 1029 // create and delete shaders 1030 { 1031 TestCaseGroup* createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests"); 1032 addChild(createDeleteGroup); 1033 1034 createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_vertex_shader", "Create vertex shader object", glu::SHADERTYPE_VERTEX)); 1035 createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_fragment_shader", "Create fragment shader object", glu::SHADERTYPE_FRAGMENT)); 1036 1037 createDeleteGroup->addChild(new DeleteShaderCase(m_context, "delete_vertex_fragment", "Delete vertex shader and fragment shader")); 1038 } 1039 1040 // compile and link 1041 { 1042 TestCaseGroup* compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests"); 1043 addChild(compileLinkGroup); 1044 1045 compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_vertex_shader", "Compile vertex shader", glu::SHADERTYPE_VERTEX)); 1046 compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_fragment_shader", "Compile fragment shader", glu::SHADERTYPE_FRAGMENT)); 1047 1048 compileLinkGroup->addChild(new LinkVertexFragmentCase(m_context, "link_vertex_fragment", "Link vertex and fragment shaders")); 1049 } 1050 1051 // shader source 1052 { 1053 TestCaseGroup* shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests"); 1054 addChild(shaderSourceGroup); 1055 1056 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 1057 { 1058 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 1059 1060 const std::string caseName = std::string("replace_source") + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex"); 1061 const std::string caseDesc = std::string("Replace source code of ") + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "fragment" : "vertex") + " shader."; 1062 1063 shaderSourceGroup->addChild(new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType)); 1064 } 1065 1066 for (int stringLengthsInt = 0; stringLengthsInt < 3; stringLengthsInt++) 1067 for (int caseNdx = 1; caseNdx <= 3; caseNdx++) 1068 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++) 1069 { 1070 const int numSlices = 1 << caseNdx; 1071 const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX; 1072 1073 const bool explicitLengths = (stringLengthsInt != 0); 1074 const bool randomNullTerm = (stringLengthsInt == 2); 1075 1076 const deUint32 flags = (explicitLengths ? CASE_EXPLICIT_SOURCE_LENGTHS : 0) 1077 | (randomNullTerm ? CASE_RANDOM_NULL_TERMINATED : 0); 1078 1079 const std::string caseName = "split_source_" 1080 + de::toString(numSlices) 1081 + (randomNullTerm ? "_random_negative_length" : (explicitLengths ? "_specify_lengths" : "_null_terminated")) 1082 + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex"); 1083 1084 const std::string caseDesc = std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex") 1085 + " shader source split into " 1086 + de::toString(numSlices) 1087 + " pieces" 1088 + (explicitLengths ? ", using explicitly specified string lengths" : "") 1089 + (randomNullTerm ? " with random negative length values" : ""); 1090 1091 shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType, numSlices, flags)); 1092 } 1093 } 1094 1095 // link status and infolog 1096 { 1097 TestCaseGroup* linkStatusGroup = new TestCaseGroup(m_context, "program_state", "Program state persistence tests"); 1098 addChild(linkStatusGroup); 1099 1100 addProgramStateCase<ProgramStateDetachShaderCase> (linkStatusGroup, m_context, "detach_shader", "detach shader"); 1101 addProgramStateCase<ProgramStateReattachShaderCase> (linkStatusGroup, m_context, "reattach_shader", "reattach shader"); 1102 addProgramStateCase<ProgramStateDeleteShaderCase> (linkStatusGroup, m_context, "delete_shader", "delete shader"); 1103 addProgramStateCase<ProgramStateReplaceShaderCase> (linkStatusGroup, m_context, "replace_shader", "replace shader object"); 1104 addProgramStateCase<ProgramStateRecompileShaderCase> (linkStatusGroup, m_context, "recompile_shader", "recompile shader"); 1105 addProgramStateCase<ProgramStateReplaceSourceCase> (linkStatusGroup, m_context, "replace_source", "replace shader source"); 1106 } 1107 } 1108 1109 } // Functional 1110 } // gles2 1111 } // deqp 1112