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