1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 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 Wrapper for GL program object. 22 *//*--------------------------------------------------------------------*/ 23 24#include "gluShaderProgram.hpp" 25#include "gluRenderContext.hpp" 26#include "glwFunctions.hpp" 27#include "glwEnums.hpp" 28#include "tcuTestLog.hpp" 29#include "deClock.h" 30 31#include <cstring> 32 33using std::string; 34 35namespace glu 36{ 37 38// Shader 39 40Shader::Shader (const RenderContext& renderCtx, ShaderType shaderType) 41 : m_gl (renderCtx.getFunctions()) 42 , m_shader (0) 43{ 44 m_info.type = shaderType; 45 m_shader = m_gl.createShader(getGLShaderType(shaderType)); 46 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()"); 47 TCU_CHECK(m_shader); 48} 49 50Shader::Shader (const glw::Functions& gl, ShaderType shaderType) 51 : m_gl (gl) 52 , m_shader (0) 53{ 54 m_info.type = shaderType; 55 m_shader = m_gl.createShader(getGLShaderType(shaderType)); 56 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader()"); 57 TCU_CHECK(m_shader); 58} 59 60Shader::~Shader (void) 61{ 62 m_gl.deleteShader(m_shader); 63} 64 65void Shader::setSources (int numSourceStrings, const char* const* sourceStrings, const int* lengths) 66{ 67 m_gl.shaderSource(m_shader, numSourceStrings, sourceStrings, lengths); 68 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource()"); 69 70 m_info.source.clear(); 71 for (int ndx = 0; ndx < numSourceStrings; ndx++) 72 { 73 const size_t length = lengths && lengths[ndx] >= 0 ? lengths[ndx] : strlen(sourceStrings[ndx]); 74 m_info.source += std::string(sourceStrings[ndx], length); 75 } 76} 77 78void Shader::compile (void) 79{ 80 m_info.compileOk = false; 81 m_info.compileTimeUs = 0; 82 m_info.infoLog.clear(); 83 84 { 85 deUint64 compileStart = deGetMicroseconds(); 86 m_gl.compileShader(m_shader); 87 m_info.compileTimeUs = deGetMicroseconds() - compileStart; 88 } 89 90 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader()"); 91 92 // Query status 93 { 94 int compileStatus = 0; 95 96 m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus); 97 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); 98 99 m_info.compileOk = compileStatus != GL_FALSE; 100 } 101 102 // Query log 103 { 104 int infoLogLen = 0; 105 int unusedLen; 106 107 m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen); 108 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); 109 110 if (infoLogLen > 0) 111 { 112 // The INFO_LOG_LENGTH query and the buffer query implementations have 113 // very commonly off-by-one errors. Try to work around these issues. 114 115 // add tolerance for off-by-one in log length, buffer write, and for terminator 116 std::vector<char> infoLog(infoLogLen + 3, '\0'); 117 118 // claim buf size is one smaller to protect from off-by-one writing over buffer bounds 119 m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]); 120 121 if (infoLog[(int)(infoLog.size()) - 1] != '\0') 122 { 123 // return whole buffer if null terminator was overwritten 124 m_info.infoLog = std::string(&infoLog[0], infoLog.size()); 125 } 126 else 127 { 128 // read as C string. infoLog is guaranteed to be 0-terminated 129 m_info.infoLog = std::string(&infoLog[0]); 130 } 131 } 132 } 133} 134 135void Shader::specialize (const char* entryPoint, glw::GLuint numSpecializationConstants, 136 const glw::GLuint* constantIndex, const glw::GLuint* constantValue) 137{ 138 m_info.compileOk = false; 139 m_info.compileTimeUs = 0; 140 m_info.infoLog.clear(); 141 142 { 143 deUint64 compileStart = deGetMicroseconds(); 144 m_gl.specializeShader(m_shader, entryPoint, numSpecializationConstants, constantIndex, constantValue); 145 m_info.compileTimeUs = deGetMicroseconds() - compileStart; 146 } 147 148 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glSpecializeShader()"); 149 150 // Query status 151 { 152 int compileStatus = 0; 153 154 m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus); 155 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); 156 157 m_info.compileOk = compileStatus != GL_FALSE; 158 } 159 160 // Query log 161 { 162 int infoLogLen = 0; 163 int unusedLen; 164 165 m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen); 166 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); 167 168 if (infoLogLen > 0) 169 { 170 // The INFO_LOG_LENGTH query and the buffer query implementations have 171 // very commonly off-by-one errors. Try to work around these issues. 172 173 // add tolerance for off-by-one in log length, buffer write, and for terminator 174 std::vector<char> infoLog(infoLogLen + 3, '\0'); 175 176 // claim buf size is one smaller to protect from off-by-one writing over buffer bounds 177 m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]); 178 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderInfoLog()"); 179 180 if (infoLog[(int)(infoLog.size()) - 1] != '\0') 181 { 182 // return whole buffer if null terminator was overwritten 183 m_info.infoLog = std::string(&infoLog[0], infoLog.size()); 184 } 185 else 186 { 187 // read as C string. infoLog is guaranteed to be 0-terminated 188 m_info.infoLog = std::string(&infoLog[0]); 189 } 190 } 191 } 192} 193 194// Program 195 196static bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program) 197{ 198 int linkStatus = 0; 199 200 gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus); 201 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()"); 202 return (linkStatus != GL_FALSE); 203} 204 205static std::string getProgramInfoLog (const glw::Functions& gl, deUint32 program) 206{ 207 int infoLogLen = 0; 208 int unusedLen; 209 210 gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen); 211 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()"); 212 213 if (infoLogLen > 0) 214 { 215 // The INFO_LOG_LENGTH query and the buffer query implementations have 216 // very commonly off-by-one errors. Try to work around these issues. 217 218 // add tolerance for off-by-one in log length, buffer write, and for terminator 219 std::vector<char> infoLog(infoLogLen + 3, '\0'); 220 221 // claim buf size is one smaller to protect from off-by-one writing over buffer bounds 222 gl.getProgramInfoLog(program, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]); 223 224 // return whole buffer if null terminator was overwritten 225 if (infoLog[(int)(infoLog.size()) - 1] != '\0') 226 return std::string(&infoLog[0], infoLog.size()); 227 228 // read as C string. infoLog is guaranteed to be 0-terminated 229 return std::string(&infoLog[0]); 230 } 231 return std::string(); 232} 233 234Program::Program (const RenderContext& renderCtx) 235 : m_gl (renderCtx.getFunctions()) 236 , m_program (0) 237{ 238 m_program = m_gl.createProgram(); 239 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()"); 240} 241 242Program::Program (const glw::Functions& gl) 243 : m_gl (gl) 244 , m_program (0) 245{ 246 m_program = m_gl.createProgram(); 247 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateProgram()"); 248} 249 250Program::Program (const RenderContext& renderCtx, deUint32 program) 251 : m_gl (renderCtx.getFunctions()) 252 , m_program (program) 253{ 254 m_info.linkOk = getProgramLinkStatus(m_gl, program); 255 m_info.infoLog = getProgramInfoLog(m_gl, program); 256} 257 258Program::~Program (void) 259{ 260 m_gl.deleteProgram(m_program); 261} 262 263void Program::attachShader (deUint32 shader) 264{ 265 m_gl.attachShader(m_program, shader); 266 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader()"); 267} 268 269void Program::detachShader (deUint32 shader) 270{ 271 m_gl.detachShader(m_program, shader); 272 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader()"); 273} 274 275void Program::bindAttribLocation (deUint32 location, const char* name) 276{ 277 m_gl.bindAttribLocation(m_program, location, name); 278 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindAttribLocation()"); 279} 280 281void Program::transformFeedbackVaryings (int count, const char* const* varyings, deUint32 bufferMode) 282{ 283 m_gl.transformFeedbackVaryings(m_program, count, varyings, bufferMode); 284 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings()"); 285} 286 287void Program::link (void) 288{ 289 m_info.linkOk = false; 290 m_info.linkTimeUs = 0; 291 m_info.infoLog.clear(); 292 293 { 294 deUint64 linkStart = deGetMicroseconds(); 295 m_gl.linkProgram(m_program); 296 m_info.linkTimeUs = deGetMicroseconds() - linkStart; 297 } 298 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram()"); 299 300 m_info.linkOk = getProgramLinkStatus(m_gl, m_program); 301 m_info.infoLog = getProgramInfoLog(m_gl, m_program); 302} 303 304bool Program::isSeparable (void) const 305{ 306 int separable = GL_FALSE; 307 308 m_gl.getProgramiv(m_program, GL_PROGRAM_SEPARABLE, &separable); 309 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv()"); 310 311 return (separable != GL_FALSE); 312} 313 314void Program::setSeparable (bool separable) 315{ 316 m_gl.programParameteri(m_program, GL_PROGRAM_SEPARABLE, separable); 317 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glProgramParameteri()"); 318} 319 320// ProgramPipeline 321 322ProgramPipeline::ProgramPipeline (const RenderContext& renderCtx) 323 : m_gl (renderCtx.getFunctions()) 324 , m_pipeline (0) 325{ 326 m_gl.genProgramPipelines(1, &m_pipeline); 327 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()"); 328} 329 330ProgramPipeline::ProgramPipeline (const glw::Functions& gl) 331 : m_gl (gl) 332 , m_pipeline (0) 333{ 334 m_gl.genProgramPipelines(1, &m_pipeline); 335 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenProgramPipelines()"); 336} 337 338ProgramPipeline::~ProgramPipeline (void) 339{ 340 m_gl.deleteProgramPipelines(1, &m_pipeline); 341} 342 343void ProgramPipeline::useProgramStages (deUint32 stages, deUint32 program) 344{ 345 m_gl.useProgramStages(m_pipeline, stages, program); 346 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgramStages()"); 347} 348 349void ProgramPipeline::activeShaderProgram (deUint32 program) 350{ 351 m_gl.activeShaderProgram(m_pipeline, program); 352 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glActiveShaderProgram()"); 353} 354 355bool ProgramPipeline::isValid (void) 356{ 357 glw::GLint status = GL_FALSE; 358 m_gl.validateProgramPipeline(m_pipeline); 359 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glValidateProgramPipeline()"); 360 361 m_gl.getProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status); 362 363 return (status != GL_FALSE); 364} 365 366// ShaderProgram 367 368ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources) 369 : m_program(renderCtx.getFunctions()) 370{ 371 init(renderCtx.getFunctions(), sources); 372} 373 374ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries) 375 : m_program(renderCtx.getFunctions()) 376{ 377 init(renderCtx.getFunctions(), binaries); 378} 379 380ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources) 381 : m_program(gl) 382{ 383 init(gl, sources); 384} 385 386ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries) 387 : m_program(gl) 388{ 389 init(gl, binaries); 390} 391 392void ShaderProgram::init (const glw::Functions& gl, const ProgramSources& sources) 393{ 394 try 395 { 396 bool shadersOk = true; 397 398 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 399 { 400 for (int shaderNdx = 0; shaderNdx < (int)sources.sources[shaderType].size(); ++shaderNdx) 401 { 402 const char* source = sources.sources[shaderType][shaderNdx].c_str(); 403 const int length = (int)sources.sources[shaderType][shaderNdx].size(); 404 405 m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1); 406 407 m_shaders[shaderType].push_back(new Shader(gl, ShaderType(shaderType))); 408 m_shaders[shaderType].back()->setSources(1, &source, &length); 409 m_shaders[shaderType].back()->compile(); 410 411 shadersOk = shadersOk && m_shaders[shaderType].back()->getCompileStatus(); 412 } 413 } 414 415 if (shadersOk) 416 { 417 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 418 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) 419 m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader()); 420 421 for (std::vector<AttribLocationBinding>::const_iterator binding = sources.attribLocationBindings.begin(); binding != sources.attribLocationBindings.end(); ++binding) 422 m_program.bindAttribLocation(binding->location, binding->name.c_str()); 423 424 DE_ASSERT((sources.transformFeedbackBufferMode == GL_NONE) == sources.transformFeedbackVaryings.empty()); 425 if (sources.transformFeedbackBufferMode != GL_NONE) 426 { 427 std::vector<const char*> tfVaryings(sources.transformFeedbackVaryings.size()); 428 for (int ndx = 0; ndx < (int)tfVaryings.size(); ndx++) 429 tfVaryings[ndx] = sources.transformFeedbackVaryings[ndx].c_str(); 430 431 m_program.transformFeedbackVaryings((int)tfVaryings.size(), &tfVaryings[0], sources.transformFeedbackBufferMode); 432 } 433 434 if (sources.separable) 435 m_program.setSeparable(true); 436 437 m_program.link(); 438 } 439 } 440 catch (...) 441 { 442 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 443 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) 444 delete m_shaders[shaderType][shaderNdx]; 445 throw; 446 } 447} 448 449void ShaderProgram::init (const glw::Functions& gl, const ProgramBinaries& binaries) 450{ 451 try 452 { 453 bool shadersOk = true; 454 455 for (deUint32 binaryNdx = 0; binaryNdx < binaries.binaries.size(); ++binaryNdx) 456 { 457 ShaderBinary shaderBinary = binaries.binaries[binaryNdx]; 458 if (!shaderBinary.binary.empty()) 459 { 460 const char* binary = (const char*)shaderBinary.binary.data(); 461 const int length = (int)(shaderBinary.binary.size() * sizeof(deUint32)); 462 463 DE_ASSERT(shaderBinary.shaderEntryPoints.size() == shaderBinary.shaderTypes.size()); 464 465 std::vector<Shader*> shaders; 466 for (deUint32 shaderTypeNdx = 0; shaderTypeNdx < shaderBinary.shaderTypes.size(); ++shaderTypeNdx) 467 { 468 ShaderType shaderType = shaderBinary.shaderTypes[shaderTypeNdx]; 469 470 Shader* shader = new Shader(gl, ShaderType(shaderType)); 471 472 m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1); 473 m_shaders[shaderType].push_back(shader); 474 shaders.push_back(shader); 475 } 476 477 setBinary(gl, shaders, binaries.binaryFormat, binary, length); 478 479 for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) 480 { 481 shaders[shaderNdx]->specialize(shaderBinary.shaderEntryPoints[shaderNdx].c_str(), 482 (deUint32)shaderBinary.specializationIndices.size(), 483 shaderBinary.specializationIndices.data(), 484 shaderBinary.specializationValues.data()); 485 486 shadersOk = shadersOk && shaders[shaderNdx]->getCompileStatus(); 487 } 488 } 489 } 490 491 if (shadersOk) 492 { 493 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 494 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) 495 m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader()); 496 497 m_program.link(); 498 } 499 } 500 catch (...) 501 { 502 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 503 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) 504 delete m_shaders[shaderType][shaderNdx]; 505 throw; 506 } 507} 508 509void ShaderProgram::setBinary (const glw::Functions& gl, std::vector<Shader*>& shaders, glw::GLenum binaryFormat, const void* binaryData, const int length) 510{ 511 std::vector<glw::GLuint> shaderVec; 512 for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) 513 shaderVec.push_back(shaders[shaderNdx]->getShader()); 514 515 gl.shaderBinary((glw::GLsizei)shaderVec.size(), shaderVec.data(), binaryFormat, binaryData, length); 516 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderBinary"); 517 518 for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) 519 { 520 glw::GLint shaderState; 521 gl.getShaderiv(shaders[shaderNdx]->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState); 522 GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv"); 523 524 DE_ASSERT(shaderState == GL_TRUE); 525 } 526} 527 528ShaderProgram::~ShaderProgram (void) 529{ 530 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 531 for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) 532 delete m_shaders[shaderType][shaderNdx]; 533} 534 535// Utilities 536 537deUint32 getGLShaderType (ShaderType shaderType) 538{ 539 static const deUint32 s_typeMap[] = 540 { 541 GL_VERTEX_SHADER, 542 GL_FRAGMENT_SHADER, 543 GL_GEOMETRY_SHADER, 544 GL_TESS_CONTROL_SHADER, 545 GL_TESS_EVALUATION_SHADER, 546 GL_COMPUTE_SHADER, 547 0, 548 0, 549 0, 550 0, 551 0, 552 0, 553 0, 554 0, 555 }; 556 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST); 557 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap))); 558 return s_typeMap[shaderType]; 559} 560 561deUint32 getGLShaderTypeBit (ShaderType shaderType) 562{ 563 static const deUint32 s_typebitMap[] = 564 { 565 GL_VERTEX_SHADER_BIT, 566 GL_FRAGMENT_SHADER_BIT, 567 GL_GEOMETRY_SHADER_BIT, 568 GL_TESS_CONTROL_SHADER_BIT, 569 GL_TESS_EVALUATION_SHADER_BIT, 570 GL_COMPUTE_SHADER_BIT, 571 0, 572 0, 573 0, 574 0, 575 0, 576 0, 577 0, 578 0, 579 }; 580 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST); 581 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap))); 582 return s_typebitMap[shaderType]; 583} 584 585qpShaderType getLogShaderType (ShaderType shaderType) 586{ 587 static const qpShaderType s_typeMap[] = 588 { 589 QP_SHADER_TYPE_VERTEX, 590 QP_SHADER_TYPE_FRAGMENT, 591 QP_SHADER_TYPE_GEOMETRY, 592 QP_SHADER_TYPE_TESS_CONTROL, 593 QP_SHADER_TYPE_TESS_EVALUATION, 594 QP_SHADER_TYPE_COMPUTE, 595 QP_SHADER_TYPE_RAYGEN, 596 QP_SHADER_TYPE_ANY_HIT, 597 QP_SHADER_TYPE_CLOSEST_HIT, 598 QP_SHADER_TYPE_MISS, 599 QP_SHADER_TYPE_INTERSECTION, 600 QP_SHADER_TYPE_CALLABLE, 601 QP_SHADER_TYPE_TASK, 602 QP_SHADER_TYPE_MESH, 603 }; 604 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST); 605 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap))); 606 return s_typeMap[shaderType]; 607} 608 609tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo) 610{ 611 return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog); 612} 613 614tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader) 615{ 616 return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram; 617} 618 619static void logShaderProgram (tcu::TestLog& log, const ProgramInfo& programInfo, size_t numShaders, const ShaderInfo* const* shaderInfos) 620{ 621 log << tcu::TestLog::ShaderProgram(programInfo.linkOk, programInfo.infoLog); 622 try 623 { 624 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx) 625 log << *shaderInfos[shaderNdx]; 626 } 627 catch (...) 628 { 629 log << tcu::TestLog::EndShaderProgram; 630 throw; 631 } 632 log << tcu::TestLog::EndShaderProgram; 633 634 // Write statistics. 635 { 636 static const struct 637 { 638 const char* name; 639 const char* description; 640 } s_compileTimeDesc[] = 641 { 642 { "VertexCompileTime", "Vertex shader compile time" }, 643 { "FragmentCompileTime", "Fragment shader compile time" }, 644 { "GeometryCompileTime", "Geometry shader compile time" }, 645 { "TessControlCompileTime", "Tesselation control shader compile time" }, 646 { "TessEvaluationCompileTime", "Tesselation evaluation shader compile time" }, 647 { "ComputeCompileTime", "Compute shader compile time" }, 648 { "RaygenCompileTime", "Raygen shader compile time" }, 649 { "AnyHitCompileTime", "Any hit shader compile time" }, 650 { "ClosestHitCompileTime", "Closest hit shader compile time" }, 651 { "MissCompileTime", "Miss shader compile time" }, 652 { "IntersectionCompileTime", "Intersection shader compile time" }, 653 { "CallableCompileTime", "Callable shader compile time" }, 654 { "TaskCompileTime", "Task shader compile time" }, 655 { "MeshCompileTime", "Mesh shader compile time" }, 656 }; 657 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST); 658 659 bool allShadersOk = true; 660 661 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx) 662 { 663 const ShaderInfo& shaderInfo = *shaderInfos[shaderNdx]; 664 665 log << tcu::TestLog::Float(s_compileTimeDesc[shaderInfo.type].name, 666 s_compileTimeDesc[shaderInfo.type].description, 667 "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f); 668 669 allShadersOk = allShadersOk && shaderInfo.compileOk; 670 } 671 672 if (allShadersOk) 673 log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)programInfo.linkTimeUs / 1000.0f); 674 } 675} 676 677tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgramInfo& shaderProgramInfo) 678{ 679 std::vector<const ShaderInfo*> shaderPtrs (shaderProgramInfo.shaders.size()); 680 681 for (size_t ndx = 0; ndx < shaderPtrs.size(); ndx++) 682 shaderPtrs[ndx] = &shaderProgramInfo.shaders[ndx]; 683 684 logShaderProgram(log, shaderProgramInfo.program, shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]); 685 686 return log; 687} 688 689tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& shaderProgram) 690{ 691 std::vector<const ShaderInfo*> shaderPtrs; 692 693 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 694 { 695 for (int shaderNdx = 0; shaderNdx < shaderProgram.getNumShaders((ShaderType)shaderType); shaderNdx++) 696 shaderPtrs.push_back(&shaderProgram.getShaderInfo((ShaderType)shaderType, shaderNdx)); 697 } 698 699 logShaderProgram(log, shaderProgram.getProgramInfo(), shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]); 700 701 return log; 702} 703 704tcu::TestLog& operator<< (tcu::TestLog& log, const ProgramSources& sources) 705{ 706 log << tcu::TestLog::ShaderProgram(false, "(Source only)"); 707 708 try 709 { 710 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) 711 { 712 for (size_t shaderNdx = 0; shaderNdx < sources.sources[shaderType].size(); shaderNdx++) 713 { 714 log << tcu::TestLog::Shader(getLogShaderType((ShaderType)shaderType), 715 sources.sources[shaderType][shaderNdx], 716 false, ""); 717 } 718 } 719 } 720 catch (...) 721 { 722 log << tcu::TestLog::EndShaderProgram; 723 throw; 724 } 725 726 log << tcu::TestLog::EndShaderProgram; 727 728 return log; 729} 730 731} // glu 732