Home | History | Annotate | Download | only in opengl
      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
    700