xref: /aosp_15_r20/external/deqp/framework/opengl/gluShaderProgram.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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