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_renderCtx	(renderCtx)
     42 	, m_shader		(0)
     43 {
     44 	const glw::Functions& gl = m_renderCtx.getFunctions();
     45 
     46 	m_info.type	= shaderType;
     47 	m_shader	= gl.createShader(getGLShaderType(shaderType));
     48 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader()");
     49 	TCU_CHECK(m_shader);
     50 }
     51 
     52 Shader::~Shader (void)
     53 {
     54 	const glw::Functions& gl = m_renderCtx.getFunctions();
     55 	gl.deleteShader(m_shader);
     56 }
     57 
     58 void Shader::setSources (int numSourceStrings, const char* const* sourceStrings, const int* lengths)
     59 {
     60 	const glw::Functions& gl = m_renderCtx.getFunctions();
     61 
     62 	gl.shaderSource(m_shader, numSourceStrings, sourceStrings, lengths);
     63 	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource()");
     64 
     65 	m_info.source.clear();
     66 	for (int ndx = 0; ndx < numSourceStrings; ndx++)
     67 	{
     68 		const size_t length = lengths && lengths[ndx] >= 0 ? lengths[ndx] : strlen(sourceStrings[ndx]);
     69 		m_info.source += std::string(sourceStrings[ndx], length);
     70 	}
     71 }
     72 
     73 void Shader::compile (void)
     74 {
     75 	const glw::Functions& gl = m_renderCtx.getFunctions();
     76 
     77 	m_info.compileOk		= false;
     78 	m_info.compileTimeUs	= 0;
     79 	m_info.infoLog.clear();
     80 
     81 	{
     82 		deUint64 compileStart = deGetMicroseconds();
     83 		gl.compileShader(m_shader);
     84 		m_info.compileTimeUs = deGetMicroseconds() - compileStart;
     85 	}
     86 
     87 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader()");
     88 
     89 	// Query status & log.
     90 	{
     91 		int	compileStatus	= 0;
     92 		int	infoLogLen		= 0;
     93 		int	unusedLen;
     94 
     95 		gl.getShaderiv(m_shader, GL_COMPILE_STATUS,		&compileStatus);
     96 		gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH,	&infoLogLen);
     97 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
     98 
     99 		m_info.compileOk = compileStatus != GL_FALSE;
    100 
    101 		if (infoLogLen > 0)
    102 		{
    103 			std::vector<char> infoLog(infoLogLen);
    104 			gl.getShaderInfoLog(m_shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
    105 			m_info.infoLog = std::string(&infoLog[0], infoLogLen);
    106 		}
    107 	}
    108 }
    109 
    110 // Program
    111 
    112 static bool getProgramLinkStatus (const RenderContext& renderCtx, deUint32 program)
    113 {
    114 	const glw::Functions& gl	= renderCtx.getFunctions();
    115 	int	linkStatus				= 0;
    116 
    117 	gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
    118 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
    119 	return (linkStatus != GL_FALSE);
    120 }
    121 
    122 static std::string getProgramInfoLog (const RenderContext& renderCtx, deUint32 program)
    123 {
    124 	const glw::Functions& gl = renderCtx.getFunctions();
    125 
    126 	int	infoLogLen	= 0;
    127 	int	unusedLen;
    128 
    129 	gl.getProgramiv(program, GL_INFO_LOG_LENGTH,	&infoLogLen);
    130 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
    131 
    132 	if (infoLogLen > 0)
    133 	{
    134 		std::vector<char> infoLog(infoLogLen);
    135 		gl.getProgramInfoLog(program, (int)infoLog.size(), &unusedLen, &infoLog[0]);
    136 		return std::string(&infoLog[0], infoLogLen);
    137 	}
    138 	return std::string();
    139 }
    140 
    141 Program::Program (const RenderContext& renderCtx)
    142 	: m_renderCtx	(renderCtx)
    143 	, m_program		(0)
    144 {
    145 	const glw::Functions& gl = m_renderCtx.getFunctions();
    146 
    147 	m_program = gl.createProgram();
    148 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram()");
    149 }
    150 
    151 Program::Program (const RenderContext& renderCtx, deUint32 program)
    152 	: m_renderCtx	(renderCtx)
    153 	, m_program		(program)
    154 {
    155 	m_info.linkOk	= getProgramLinkStatus(renderCtx, program);
    156 	m_info.infoLog	= getProgramInfoLog(renderCtx, program);
    157 }
    158 
    159 Program::~Program (void)
    160 {
    161 	const glw::Functions& gl = m_renderCtx.getFunctions();
    162 	gl.deleteProgram(m_program);
    163 }
    164 
    165 void Program::attachShader (deUint32 shader)
    166 {
    167 	const glw::Functions& gl = m_renderCtx.getFunctions();
    168 
    169 	gl.attachShader(m_program, shader);
    170 	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader()");
    171 }
    172 
    173 void Program::detachShader (deUint32 shader)
    174 {
    175 	const glw::Functions& gl = m_renderCtx.getFunctions();
    176 
    177 	gl.detachShader(m_program, shader);
    178 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader()");
    179 }
    180 
    181 void Program::bindAttribLocation (deUint32 location, const char* name)
    182 {
    183 	const glw::Functions& gl = m_renderCtx.getFunctions();
    184 
    185 	gl.bindAttribLocation(m_program, location, name);
    186 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation()");
    187 }
    188 
    189 void Program::transformFeedbackVaryings (int count, const char* const* varyings, deUint32 bufferMode)
    190 {
    191 	const glw::Functions& gl = m_renderCtx.getFunctions();
    192 
    193 	gl.transformFeedbackVaryings(m_program, count, varyings, bufferMode);
    194 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings()");
    195 }
    196 
    197 void Program::link (void)
    198 {
    199 	const glw::Functions& gl = m_renderCtx.getFunctions();
    200 
    201 	m_info.linkOk		= false;
    202 	m_info.linkTimeUs	= 0;
    203 	m_info.infoLog.clear();
    204 
    205 	{
    206 		deUint64 linkStart = deGetMicroseconds();
    207 		gl.linkProgram(m_program);
    208 		m_info.linkTimeUs = deGetMicroseconds() - linkStart;
    209 	}
    210 	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram()");
    211 
    212 	m_info.linkOk	= getProgramLinkStatus(m_renderCtx, m_program);
    213 	m_info.infoLog	= getProgramInfoLog(m_renderCtx, m_program);
    214 }
    215 
    216 bool Program::isSeparable (void) const
    217 {
    218 	const glw::Functions& gl = m_renderCtx.getFunctions();
    219 	int separable = GL_FALSE;
    220 
    221 	gl.getProgramiv(m_program, GL_PROGRAM_SEPARABLE, &separable);
    222 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
    223 
    224 	return (separable != GL_FALSE);
    225 }
    226 
    227 void Program::setSeparable (bool separable)
    228 {
    229 	const glw::Functions& gl = m_renderCtx.getFunctions();
    230 
    231 	gl.programParameteri(m_program, GL_PROGRAM_SEPARABLE, separable);
    232 	GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri()");
    233 }
    234 
    235 // ProgramPipeline
    236 
    237 ProgramPipeline::ProgramPipeline (const RenderContext& renderCtx)
    238 	: m_renderCtx	(renderCtx)
    239 	, m_pipeline	(0)
    240 {
    241 	const glw::Functions& gl = m_renderCtx.getFunctions();
    242 
    243 	gl.genProgramPipelines(1, &m_pipeline);
    244 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines()");
    245 }
    246 
    247 ProgramPipeline::~ProgramPipeline (void)
    248 {
    249 	const glw::Functions& gl = m_renderCtx.getFunctions();
    250 	gl.deleteProgramPipelines(1, &m_pipeline);
    251 }
    252 
    253 void ProgramPipeline::useProgramStages (deUint32 stages, deUint32 program)
    254 {
    255 	const glw::Functions& gl = m_renderCtx.getFunctions();
    256 
    257 	gl.useProgramStages(m_pipeline, stages, program);
    258 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages()");
    259 }
    260 
    261 void ProgramPipeline::activeShaderProgram (deUint32 program)
    262 {
    263 	const glw::Functions& gl = m_renderCtx.getFunctions();
    264 
    265 	gl.activeShaderProgram(m_pipeline, program);
    266 	GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveShaderProgram()");
    267 }
    268 
    269 bool ProgramPipeline::isValid (void)
    270 {
    271 	const glw::Functions& gl = m_renderCtx.getFunctions();
    272 	glw::GLint status = GL_FALSE;
    273 	gl.validateProgramPipeline(m_pipeline);
    274 	GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline()");
    275 
    276 	gl.getProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status);
    277 
    278 	return (status != GL_FALSE);
    279 }
    280 
    281 // ShaderProgram
    282 
    283 ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources)
    284 	: m_program(renderCtx)
    285 {
    286 	try
    287 	{
    288 		bool shadersOk = true;
    289 
    290 		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
    291 		{
    292 			for (int shaderNdx = 0; shaderNdx < (int)sources.sources[shaderType].size(); ++shaderNdx)
    293 			{
    294 				const char* source	= sources.sources[shaderType][shaderNdx].c_str();
    295 				const int	length	= (int)sources.sources[shaderType][shaderNdx].size();
    296 
    297 				m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1);
    298 
    299 				m_shaders[shaderType].push_back(new Shader(renderCtx, ShaderType(shaderType)));
    300 				m_shaders[shaderType].back()->setSources(1, &source, &length);
    301 				m_shaders[shaderType].back()->compile();
    302 
    303 				shadersOk = shadersOk && m_shaders[shaderType].back()->getCompileStatus();
    304 			}
    305 		}
    306 
    307 		if (shadersOk)
    308 		{
    309 			for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
    310 				for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
    311 					m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader());
    312 
    313 			for (std::vector<AttribLocationBinding>::const_iterator binding = sources.attribLocationBindings.begin(); binding != sources.attribLocationBindings.end(); ++binding)
    314 				m_program.bindAttribLocation(binding->location, binding->name.c_str());
    315 
    316 			DE_ASSERT((sources.transformFeedbackBufferMode == GL_NONE) == sources.transformFeedbackVaryings.empty());
    317 			if (sources.transformFeedbackBufferMode != GL_NONE)
    318 			{
    319 				std::vector<const char*> tfVaryings(sources.transformFeedbackVaryings.size());
    320 				for (int ndx = 0; ndx < (int)tfVaryings.size(); ndx++)
    321 					tfVaryings[ndx] = sources.transformFeedbackVaryings[ndx].c_str();
    322 
    323 				m_program.transformFeedbackVaryings((int)tfVaryings.size(), &tfVaryings[0], sources.transformFeedbackBufferMode);
    324 			}
    325 
    326 			if (sources.separable)
    327 				m_program.setSeparable(true);
    328 
    329 			m_program.link();
    330 		}
    331 	}
    332 	catch (...)
    333 	{
    334 		for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
    335 			for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
    336 				delete m_shaders[shaderType][shaderNdx];
    337 		throw;
    338 	}
    339 }
    340 
    341 ShaderProgram::~ShaderProgram (void)
    342 {
    343 	for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++)
    344 		for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx)
    345 			delete m_shaders[shaderType][shaderNdx];
    346 }
    347 
    348 // Utilities
    349 
    350 deUint32 getGLShaderType (ShaderType shaderType)
    351 {
    352 	static const deUint32 s_typeMap[] =
    353 	{
    354 		GL_VERTEX_SHADER,
    355 		GL_FRAGMENT_SHADER,
    356 		GL_GEOMETRY_SHADER,
    357 		GL_TESS_CONTROL_SHADER,
    358 		GL_TESS_EVALUATION_SHADER,
    359 		GL_COMPUTE_SHADER
    360 	};
    361 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
    362 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
    363 	return s_typeMap[shaderType];
    364 }
    365 
    366 deUint32 getGLShaderTypeBit (ShaderType shaderType)
    367 {
    368 	static const deUint32 s_typebitMap[] =
    369 	{
    370 		GL_VERTEX_SHADER_BIT,
    371 		GL_FRAGMENT_SHADER_BIT,
    372 		GL_GEOMETRY_SHADER_BIT,
    373 		GL_TESS_CONTROL_SHADER_BIT,
    374 		GL_TESS_EVALUATION_SHADER_BIT,
    375 		GL_COMPUTE_SHADER_BIT
    376 	};
    377 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typebitMap) == SHADERTYPE_LAST);
    378 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typebitMap)));
    379 	return s_typebitMap[shaderType];
    380 }
    381 
    382 qpShaderType getLogShaderType (ShaderType shaderType)
    383 {
    384 	static const qpShaderType s_typeMap[] =
    385 	{
    386 		QP_SHADER_TYPE_VERTEX,
    387 		QP_SHADER_TYPE_FRAGMENT,
    388 		QP_SHADER_TYPE_GEOMETRY,
    389 		QP_SHADER_TYPE_TESS_CONTROL,
    390 		QP_SHADER_TYPE_TESS_EVALUATION,
    391 		QP_SHADER_TYPE_COMPUTE
    392 	};
    393 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_typeMap) == SHADERTYPE_LAST);
    394 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_typeMap)));
    395 	return s_typeMap[shaderType];
    396 }
    397 
    398 static tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderInfo& shaderInfo)
    399 {
    400 	return log << tcu::TestLog::Shader(getLogShaderType(shaderInfo.type), shaderInfo.source, shaderInfo.compileOk, shaderInfo.infoLog);
    401 }
    402 
    403 tcu::TestLog& operator<< (tcu::TestLog& log, const Shader& shader)
    404 {
    405 	return log << tcu::TestLog::ShaderProgram(false, "Plain shader") << shader.getInfo() << tcu::TestLog::EndShaderProgram;
    406 }
    407 
    408 tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderProgram& program)
    409 {
    410 	const ProgramInfo& progInfo = program.getProgramInfo();
    411 
    412 	log << tcu::TestLog::ShaderProgram(progInfo.linkOk, progInfo.infoLog);
    413 	try
    414 	{
    415 		for (int shaderTypeNdx = 0; shaderTypeNdx < SHADERTYPE_LAST; shaderTypeNdx++)
    416 		{
    417 			const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
    418 
    419 			for (int shaderNdx = 0; shaderNdx < program.getNumShaders(shaderType); ++shaderNdx)
    420 				log << program.getShaderInfo(shaderType, shaderNdx);
    421 		}
    422 	}
    423 	catch (...)
    424 	{
    425 		log << tcu::TestLog::EndShaderProgram;
    426 		throw;
    427 	}
    428 	log << tcu::TestLog::EndShaderProgram;
    429 
    430 	// Write statistics.
    431 	{
    432 		static const struct
    433 		{
    434 			const char*		name;
    435 			const char*		description;
    436 		} s_compileTimeDesc[] =
    437 		{
    438 			{ "VertexCompileTime",			"Vertex shader compile time"					},
    439 			{ "FragmentCompileTime",		"Fragment shader compile time"					},
    440 			{ "GeometryCompileTime",		"Geometry shader compile time"					},
    441 			{ "TessControlCompileTime",		"Tesselation control shader compile time"		},
    442 			{ "TessEvaluationCompileTime",	"Tesselation evaluation shader compile time"	},
    443 			{ "ComputeCompileTime",			"Compute shader compile time"					},
    444 		};
    445 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_compileTimeDesc) == SHADERTYPE_LAST);
    446 
    447 		bool allShadersOk = true;
    448 
    449 		for (int shaderTypeNdx = 0; shaderTypeNdx < SHADERTYPE_LAST; shaderTypeNdx++)
    450 		{
    451 			const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
    452 
    453 			for (int shaderNdx = 0; shaderNdx < program.getNumShaders(shaderType); ++shaderNdx)
    454 			{
    455 				const ShaderInfo& shaderInfo = program.getShaderInfo(shaderType, shaderNdx);
    456 				log << tcu::TestLog::Float(s_compileTimeDesc[shaderType].name, s_compileTimeDesc[shaderType].description, "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
    457 				allShadersOk = allShadersOk && shaderInfo.compileOk;
    458 			}
    459 		}
    460 
    461 		if (allShadersOk)
    462 			log << tcu::TestLog::Float("LinkTime", "Link time", "ms", QP_KEY_TAG_TIME, (float)progInfo.linkTimeUs / 1000.0f);
    463 	}
    464 
    465 	return log;
    466 }
    467 
    468 } // glu
    469