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)
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
Shader(const glw::Functions & gl,ShaderType shaderType)50 Shader::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
~Shader(void)60 Shader::~Shader (void)
61 {
62 m_gl.deleteShader(m_shader);
63 }
64
setSources(int numSourceStrings,const char * const * sourceStrings,const int * lengths)65 void 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
compile(void)78 void 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
specialize(const char * entryPoint,glw::GLuint numSpecializationConstants,const glw::GLuint * constantIndex,const glw::GLuint * constantValue)135 void 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
getProgramLinkStatus(const glw::Functions & gl,deUint32 program)196 static 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
getProgramInfoLog(const glw::Functions & gl,deUint32 program)205 static 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
Program(const RenderContext & renderCtx)234 Program::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
Program(const glw::Functions & gl)242 Program::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
Program(const RenderContext & renderCtx,deUint32 program)250 Program::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
~Program(void)258 Program::~Program (void)
259 {
260 m_gl.deleteProgram(m_program);
261 }
262
attachShader(deUint32 shader)263 void Program::attachShader (deUint32 shader)
264 {
265 m_gl.attachShader(m_program, shader);
266 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader()");
267 }
268
detachShader(deUint32 shader)269 void Program::detachShader (deUint32 shader)
270 {
271 m_gl.detachShader(m_program, shader);
272 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader()");
273 }
274
bindAttribLocation(deUint32 location,const char * name)275 void 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
transformFeedbackVaryings(int count,const char * const * varyings,deUint32 bufferMode)281 void 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
link(void)287 void 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
isSeparable(void) const304 bool 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
setSeparable(bool separable)314 void 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
ProgramPipeline(const RenderContext & renderCtx)322 ProgramPipeline::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
ProgramPipeline(const glw::Functions & gl)330 ProgramPipeline::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
~ProgramPipeline(void)338 ProgramPipeline::~ProgramPipeline (void)
339 {
340 m_gl.deleteProgramPipelines(1, &m_pipeline);
341 }
342
useProgramStages(deUint32 stages,deUint32 program)343 void 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
activeShaderProgram(deUint32 program)349 void ProgramPipeline::activeShaderProgram (deUint32 program)
350 {
351 m_gl.activeShaderProgram(m_pipeline, program);
352 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glActiveShaderProgram()");
353 }
354
isValid(void)355 bool 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
ShaderProgram(const RenderContext & renderCtx,const ProgramSources & sources)368 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
369 : m_program(renderCtx.getFunctions())
370 {
371 init(renderCtx.getFunctions(), sources);
372 }
373
ShaderProgram(const RenderContext & renderCtx,const ProgramBinaries & binaries)374 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries)
375 : m_program(renderCtx.getFunctions())
376 {
377 init(renderCtx.getFunctions(), binaries);
378 }
379
ShaderProgram(const glw::Functions & gl,const ProgramSources & sources)380 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources)
381 : m_program(gl)
382 {
383 init(gl, sources);
384 }
385
ShaderProgram(const glw::Functions & gl,const ProgramBinaries & binaries)386 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries)
387 : m_program(gl)
388 {
389 init(gl, binaries);
390 }
391
init(const glw::Functions & gl,const ProgramSources & sources)392 void 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
init(const glw::Functions & gl,const ProgramBinaries & binaries)449 void 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
setBinary(const glw::Functions & gl,std::vector<Shader * > & shaders,glw::GLenum binaryFormat,const void * binaryData,const int length)509 void 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
~ShaderProgram(void)528 ShaderProgram::~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
getGLShaderType(ShaderType shaderType)537 deUint32 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
getGLShaderTypeBit(ShaderType shaderType)561 deUint32 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
getLogShaderType(ShaderType shaderType)585 qpShaderType 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
operator <<(tcu::TestLog & log,const ShaderInfo & shaderInfo)609 tcu::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
operator <<(tcu::TestLog & log,const Shader & shader)614 tcu::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
logShaderProgram(tcu::TestLog & log,const ProgramInfo & programInfo,size_t numShaders,const ShaderInfo * const * shaderInfos)619 static 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
operator <<(tcu::TestLog & log,const ShaderProgramInfo & shaderProgramInfo)677 tcu::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
operator <<(tcu::TestLog & log,const ShaderProgram & shaderProgram)689 tcu::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
operator <<(tcu::TestLog & log,const ProgramSources & sources)704 tcu::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