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 	};
554 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
555 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
556 	return s_typeMap[shaderType];
557 }
558 
getGLShaderTypeBit(ShaderType shaderType)559 deUint32 getGLShaderTypeBit (ShaderType shaderType)
560 {
561 	static const deUint32 s_typebitMap[] =
562 	{
563 		GL_VERTEX_SHADER_BIT,
564 		GL_FRAGMENT_SHADER_BIT,
565 		GL_GEOMETRY_SHADER_BIT,
566 		GL_TESS_CONTROL_SHADER_BIT,
567 		GL_TESS_EVALUATION_SHADER_BIT,
568 		GL_COMPUTE_SHADER_BIT,
569 		0,
570 		0,
571 		0,
572 		0,
573 		0,
574 		0
575 	};
576 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
577 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
578 	return s_typebitMap[shaderType];
579 }
580 
getLogShaderType(ShaderType shaderType)581 qpShaderType getLogShaderType (ShaderType shaderType)
582 {
583 	static const qpShaderType s_typeMap[] =
584 	{
585 		QP_SHADER_TYPE_VERTEX,
586 		QP_SHADER_TYPE_FRAGMENT,
587 		QP_SHADER_TYPE_GEOMETRY,
588 		QP_SHADER_TYPE_TESS_CONTROL,
589 		QP_SHADER_TYPE_TESS_EVALUATION,
590 		QP_SHADER_TYPE_COMPUTE,
591 		QP_SHADER_TYPE_RAYGEN,
592 		QP_SHADER_TYPE_ANY_HIT,
593 		QP_SHADER_TYPE_CLOSEST_HIT,
594 		QP_SHADER_TYPE_MISS,
595 		QP_SHADER_TYPE_INTERSECTION,
596 		QP_SHADER_TYPE_CALLABLE,
597 	};
598 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
599 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
600 	return s_typeMap[shaderType];
601 }
602 
operator <<(tcu::TestLog & log,const ShaderInfo & shaderInfo)603 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
604 {
605 	return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
606 }
607 
operator <<(tcu::TestLog & log,const Shader & shader)608 tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
609 {
610 	return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
611 }
612 
logShaderProgram(tcu::TestLog & log,const ProgramInfo & programInfo,size_t numShaders,const ShaderInfo * const * shaderInfos)613 static void logShaderProgram (tcu::TestLog& log, const ProgramInfo& programInfo, size_t numShaders, const ShaderInfo* const* shaderInfos)
614 {
615 	log << tcu::TestLog::ShaderProgram(programInfo.linkOk, programInfo.infoLog);
616 	try
617 	{
618 		for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
619 			log << *shaderInfos[shaderNdx];
620 	}
621 	catch (...)
622 	{
623 		log << tcu::TestLog::EndShaderProgram;
624 		throw;
625 	}
626 	log << tcu::TestLog::EndShaderProgram;
627 
628 	// Write statistics.
629 	{
630 		static const struct
631 		{
632 			const char*		name;
633 			const char*		description;
634 		} s_compileTimeDesc[] =
635 		{
636 			{ "VertexCompileTime",			"Vertex shader compile time"					},
637 			{ "FragmentCompileTime",		"Fragment shader compile time"					},
638 			{ "GeometryCompileTime",		"Geometry shader compile time"					},
639 			{ "TessControlCompileTime",		"Tesselation control shader compile time"		},
640 			{ "TessEvaluationCompileTime",	"Tesselation evaluation shader compile time"	},
641 			{ "ComputeCompileTime",			"Compute shader compile time"					},
642 			{ "RaygenCompileTime",			"Raygen shader compile time"					},
643 			{ "AnyHitCompileTime",			"Any hit shader compile time"					},
644 			{ "ClosestHitCompileTime",		"Closest hit shader compile time"				},
645 			{ "MissCompileTime",			"Miss shader compile time"						},
646 			{ "IntersectionCompileTime",	"Intersection shader compile time"				},
647 			{ "CallableCompileTime",		"Callable shader compile time"					},
648 		};
649 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
650 
651 		bool allShadersOk = true;
652 
653 		for (size_t shaderNdx = 0; shaderNdx < numShaders; ++shaderNdx)
654 		{
655 			const ShaderInfo&	shaderInfo	= *shaderInfos[shaderNdx];
656 
657 			log << tcu::TestLog::Float(s_compileTimeDesc[shaderInfo.type].name,
658 									   s_compileTimeDesc[shaderInfo.type].description,
659 									   "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
660 
661 			allShadersOk = allShadersOk && shaderInfo.compileOk;
662 		}
663 
664 		if (allShadersOk)
665 			log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)programInfo.linkTimeUs / 1000.0f);
666 	}
667 }
668 
operator <<(tcu::TestLog & log,const ShaderProgramInfo & shaderProgramInfo)669 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgramInfo& shaderProgramInfo)
670 {
671 	std::vector<const ShaderInfo*>	shaderPtrs	(shaderProgramInfo.shaders.size());
672 
673 	for (size_t ndx = 0; ndx < shaderPtrs.size(); ndx++)
674 		shaderPtrs[ndx] = &shaderProgramInfo.shaders[ndx];
675 
676 	logShaderProgram(log, shaderProgramInfo.program, shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
677 
678 	return log;
679 }
680 
operator <<(tcu::TestLog & log,const ShaderProgram & shaderProgram)681 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& shaderProgram)
682 {
683 	std::vector<const ShaderInfo*>	shaderPtrs;
684 
685 	for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
686 	{
687 		for (int shaderNdx = 0; shaderNdx < shaderProgram.getNumShaders((ShaderType)shaderType); shaderNdx++)
688 			shaderPtrs.push_back(&shaderProgram.getShaderInfo((ShaderType)shaderType, shaderNdx));
689 	}
690 
691 	logShaderProgram(log, shaderProgram.getProgramInfo(), shaderPtrs.size(), shaderPtrs.empty() ? DE_NULL : &shaderPtrs[0]);
692 
693 	return log;
694 }
695 
operator <<(tcu::TestLog & log,const ProgramSources & sources)696 tcu::TestLog& operator<< (tcu::TestLog& log, const ProgramSources& sources)
697 {
698 	log << tcu::TestLog::ShaderProgram(false, "(Source only)");
699 
700 	try
701 	{
702 		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
703 		{
704 			for (size_t shaderNdx = 0; shaderNdx < sources.sources[shaderType].size(); shaderNdx++)
705 			{
706 				log << tcu::TestLog::Shader(getLogShaderType((ShaderType)shaderType),
707 											sources.sources[shaderType][shaderNdx],
708 											false, "");
709 			}
710 		}
711 	}
712 	catch (...)
713 	{
714 		log << tcu::TestLog::EndShaderProgram;
715 		throw;
716 	}
717 
718 	log << tcu::TestLog::EndShaderProgram;
719 
720 	return log;
721 }
722 
723 } // glu
724