Add CTS_ARB_gl_spirv test implementation
[platform/upstream/VK-GL-CTS.git] / framework / opengl / gluShaderProgram.cpp
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
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
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
60 Shader::~Shader (void)
61 {
62         m_gl.deleteShader(m_shader);
63 }
64
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
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
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
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
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
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
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
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
258 Program::~Program (void)
259 {
260         m_gl.deleteProgram(m_program);
261 }
262
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
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
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
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
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
304 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
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
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
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
338 ProgramPipeline::~ProgramPipeline (void)
339 {
340         m_gl.deleteProgramPipelines(1, &m_pipeline);
341 }
342
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
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
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
368 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
369         : m_program(renderCtx.getFunctions())
370 {
371         init(renderCtx.getFunctions(), sources);
372 }
373
374 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries)
375         : m_program(renderCtx.getFunctions())
376 {
377         init(renderCtx.getFunctions(), binaries);
378 }
379
380 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources)
381         : m_program(gl)
382 {
383         init(gl, sources);
384 }
385
386 ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries)
387         : m_program(gl)
388 {
389         init(gl, binaries);
390 }
391
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
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
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
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
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         };
548         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
549         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
550         return s_typeMap[shaderType];
551 }
552
553 deUint32 getGLShaderTypeBit (ShaderType shaderType)
554 {
555         static const deUint32 s_typebitMap[] =
556         {
557                 GL_VERTEX_SHADER_BIT,
558                 GL_FRAGMENT_SHADER_BIT,
559                 GL_GEOMETRY_SHADER_BIT,
560                 GL_TESS_CONTROL_SHADER_BIT,
561                 GL_TESS_EVALUATION_SHADER_BIT,
562                 GL_COMPUTE_SHADER_BIT
563         };
564         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
565         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
566         return s_typebitMap[shaderType];
567 }
568
569 qpShaderType getLogShaderType (ShaderType shaderType)
570 {
571         static const qpShaderType s_typeMap[] =
572         {
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         };
580         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
581         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
582         return s_typeMap[shaderType];
583 }
584
585 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
586 {
587         return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
588 }
589
590 tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
591 {
592         return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
593 }
594
595 static void logShaderProgram (tcu::TestLog& log, const ProgramInfo& programInfo, size_t numShaders, const ShaderInfo* const* shaderInfos)
596 {
597         log << tcu::TestLog::ShaderProgram(programInfo.linkOk, programInfo.infoLog);
598         try
599         {
600                 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
601                         log << *shaderInfos[shaderNdx];
602         }
603         catch (...)
604         {
605                 log << tcu::TestLog::EndShaderProgram;
606                 throw;
607         }
608         log << tcu::TestLog::EndShaderProgram;
609
610         // Write statistics.
611         {
612                 static const struct
613                 {
614                         const char*             name;
615                         const char*             description;
616                 } s_compileTimeDesc[] =
617                 {
618                         { "VertexCompileTime",                  "Vertex shader compile time"                                    },
619                         { "FragmentCompileTime",                "Fragment shader compile time"                                  },
620                         { "GeometryCompileTime",                "Geometry shader compile time"                                  },
621                         { "TessControlCompileTime",             "Tesselation control shader compile time"               },
622                         { "TessEvaluationCompileTime",  "Tesselation evaluation shader compile time"    },
623                         { "ComputeCompileTime",                 "Compute shader compile time"                                   },
624                 };
625                 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
626
627                 bool allShadersOk = true;
628
629                 for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
630                 {
631                         const ShaderInfo&       shaderInfo      = *shaderInfos[shaderNdx];
632
633                         log << tcu::TestLog::Float(s_compileTimeDesc[shaderInfo.type].name,
634                                                                            s_compileTimeDesc[shaderInfo.type].description,
635                                                                            "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
636
637                         allShadersOk = allShadersOk && shaderInfo.compileOk;
638                 }
639
640                 if (allShadersOk)
641                         log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)programInfo.linkTimeUs / 1000.0f);
642         }
643 }
644
645 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgramInfo& shaderProgramInfo)
646 {
647         std::vector<const ShaderInfo*>  shaderPtrs      (shaderProgramInfo.shaders.size());
648
649         for (size_t ndx = 0; ndx < shaderPtrs.size(); ndx++)
650                 shaderPtrs[ndx] = &shaderProgramInfo.shaders[ndx];
651
652         logShaderProgram(log, shaderProgramInfo.program, shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
653
654         return log;
655 }
656
657 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& shaderProgram)
658 {
659         std::vector<const ShaderInfo*>  shaderPtrs;
660
661         for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
662         {
663                 for (int shaderNdx = 0; shaderNdx < shaderProgram.getNumShaders((ShaderType)shaderType); shaderNdx++)
664                         shaderPtrs.push_back(&shaderProgram.getShaderInfo((ShaderType)shaderType, shaderNdx));
665         }
666
667         logShaderProgram(log, shaderProgram.getProgramInfo(), shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
668
669         return log;
670 }
671
672 tcu::TestLog& operator<< (tcu::TestLog& log, const ProgramSources& sources)
673 {
674         log << tcu::TestLog::ShaderProgram(false, "(Source only)");
675
676         try
677         {
678                 for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
679                 {
680                         for (size_t shaderNdx = 0; shaderNdx < sources.sources[shaderType].size(); shaderNdx++)
681                         {
682                                 log << tcu::TestLog::Shader(getLogShaderType((ShaderType)shaderType),
683                                                                                         sources.sources[shaderType][shaderNdx],
684                                                                                         false, "");
685                         }
686                 }
687         }
688         catch (...)
689         {
690                 log << tcu::TestLog::EndShaderProgram;
691                 throw;
692         }
693
694         log << tcu::TestLog::EndShaderProgram;
695
696         return log;
697 }
698
699 } // glu