Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 Module
      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 Shader API tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fShaderApiTests.hpp"
     25 #include "es2fApiCase.hpp"
     26 #include "tcuTestLog.hpp"
     27 
     28 #include "gluRenderContext.hpp"
     29 #include "gluShaderProgram.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "glwFunctions.hpp"
     32 #include "glwDefs.hpp"
     33 #include "glwEnums.hpp"
     34 
     35 #include "deString.h"
     36 
     37 #include "deRandom.hpp"
     38 #include "deStringUtil.hpp"
     39 
     40 #include <string>
     41 #include <vector>
     42 #include <map>
     43 
     44 using namespace glw; // GL types
     45 
     46 namespace deqp
     47 {
     48 namespace gles2
     49 {
     50 namespace Functional
     51 {
     52 
     53 using tcu::TestLog;
     54 
     55 namespace
     56 {
     57 
     58 enum ShaderSourceCaseFlags
     59 {
     60 	CASE_EXPLICIT_SOURCE_LENGTHS	= 1,
     61 	CASE_RANDOM_NULL_TERMINATED		= 2
     62 };
     63 
     64 struct ShaderSources
     65 {
     66 	std::vector<std::string>	strings;
     67 	std::vector<int>			lengths;
     68 };
     69 
     70 // Simple shaders
     71 
     72 const char* getSimpleShaderSource (const glu::ShaderType shaderType)
     73 {
     74 	const char* simpleVertexShaderSource	= "void main (void) { gl_Position = vec4(0.0); }\n";
     75 	const char* simpleFragmentShaderSource	= "void main (void) { gl_FragColor = vec4(0.0); }\n";
     76 
     77 	switch (shaderType)
     78 	{
     79 		case glu::SHADERTYPE_VERTEX:
     80 			return simpleVertexShaderSource;
     81 		case glu::SHADERTYPE_FRAGMENT:
     82 			return simpleFragmentShaderSource;
     83 		default:
     84 			DE_ASSERT(DE_FALSE);
     85 	}
     86 
     87 	return 0;
     88 }
     89 
     90 void setShaderSources (glu::Shader& shader, const ShaderSources& sources)
     91 {
     92 	std::vector<const char*> cStrings (sources.strings.size(), 0);
     93 
     94 	for (size_t ndx = 0; ndx < sources.strings.size(); ndx++)
     95 		cStrings[ndx] = sources.strings[ndx].c_str();
     96 
     97 	if (sources.lengths.size() > 0)
     98 		shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]);
     99 	else
    100 		shader.setSources((int)cStrings.size(), &cStrings[0], 0);
    101 }
    102 
    103 void sliceSourceString (const std::string& in, ShaderSources& out, const int numSlices, const size_t paddingLength = 0)
    104 {
    105 	DE_ASSERT(numSlices > 0);
    106 
    107 	const size_t		sliceSize			= in.length() / numSlices;
    108 	const size_t		sliceSizeRemainder	= in.length() - (sliceSize * numSlices);
    109 	const std::string	padding				(paddingLength, 'E');
    110 
    111 	for (int i = 0; i < numSlices; i++)
    112 	{
    113 		out.strings.push_back(in.substr(i * sliceSize, sliceSize) + padding);
    114 
    115 		if (paddingLength > 0)
    116 			out.lengths.push_back((int)sliceSize);
    117 	}
    118 
    119 	if (sliceSizeRemainder > 0)
    120 	{
    121 		const std::string	lastString			= in.substr(numSlices * sliceSize);
    122 		const int			lastStringLength	= (int)lastString.length();
    123 
    124 		out.strings.push_back(lastString + padding);
    125 
    126 		if (paddingLength > 0)
    127 			out.lengths.push_back(lastStringLength);
    128 	}
    129 }
    130 
    131 void queryShaderInfo (glu::RenderContext& renderCtx, deUint32 shader, glu::ShaderInfo& info)
    132 {
    133 	const glw::Functions& gl = renderCtx.getFunctions();
    134 
    135 	info.compileOk		= false;
    136 	info.compileTimeUs	= 0;
    137 	info.infoLog.clear();
    138 
    139 	// Query source, status & log.
    140 	{
    141 		int	compileStatus	= 0;
    142 		int sourceLen		= 0;
    143 		int	infoLogLen		= 0;
    144 		int	unusedLen;
    145 
    146 		gl.getShaderiv(shader, GL_COMPILE_STATUS,			&compileStatus);
    147 		gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH,	&sourceLen);
    148 		gl.getShaderiv(shader, GL_INFO_LOG_LENGTH,		&infoLogLen);
    149 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
    150 
    151 		info.compileOk = compileStatus != GL_FALSE;
    152 
    153 		if (sourceLen > 0)
    154 		{
    155 			std::vector<char> source(sourceLen);
    156 			gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]);
    157 			info.source = std::string(&source[0], sourceLen);
    158 		}
    159 
    160 		if (infoLogLen > 0)
    161 		{
    162 			std::vector<char> infoLog(infoLogLen);
    163 			gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
    164 			info.infoLog = std::string(&infoLog[0], infoLogLen);
    165 		}
    166 	}
    167 }
    168 
    169 // Shader source generator
    170 
    171 class SourceGenerator
    172 {
    173 public:
    174 	virtual				~SourceGenerator	(void)	{}
    175 
    176 	virtual std::string	next				(const glu::ShaderType shaderType)			= 0;
    177 	virtual bool		finished			(const glu::ShaderType shaderType) const	= 0;
    178 };
    179 
    180 class ConstantShaderGenerator : public SourceGenerator
    181 {
    182 public:
    183 				ConstantShaderGenerator		(de::Random& rnd)	: m_rnd(rnd)	{}
    184 				~ConstantShaderGenerator	(void)								{}
    185 
    186 	bool		finished					(const glu::ShaderType shaderType) const	{ DE_UNREF(shaderType); return false; }
    187 
    188 	std::string	next						(const glu::ShaderType shaderType);
    189 
    190 private:
    191 	de::Random	m_rnd;
    192 };
    193 
    194 std::string ConstantShaderGenerator::next (const glu::ShaderType shaderType)
    195 {
    196 	DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
    197 
    198 	const float			value		= m_rnd.getFloat(0.0f, 1.0f);
    199 	const std::string	valueString	= de::toString(value);
    200 	const std::string	outputName	= (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "gl_FragColor";
    201 
    202 	std::string source =
    203 		"#version 100\n"
    204 		"void main (void) { " + outputName + " = vec4(" + valueString + "); }\n";
    205 
    206 	return source;
    207 }
    208 
    209 // Shader allocation utility
    210 
    211 class ShaderAllocator
    212 {
    213 public:
    214 					ShaderAllocator		(glu::RenderContext& context, SourceGenerator& generator);
    215 					~ShaderAllocator	(void);
    216 
    217 	bool			hasShader			(const glu::ShaderType shaderType);
    218 
    219 	void			setSource			(const glu::ShaderType shaderType);
    220 
    221 	glu::Shader&	createShader		(const glu::ShaderType shaderType);
    222 	void			deleteShader		(const glu::ShaderType shaderType);
    223 
    224 	glu::Shader&	get					(const glu::ShaderType shaderType)	{ DE_ASSERT(hasShader(shaderType)); return *m_shaders[shaderType]; }
    225 
    226 private:
    227 	const glu::RenderContext&				m_context;
    228 	SourceGenerator&						m_srcGen;
    229 	std::map<glu::ShaderType, glu::Shader*>	m_shaders;
    230 };
    231 
    232 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator)
    233 	: m_context	(context)
    234 	, m_srcGen	(generator)
    235 {
    236 }
    237 
    238 ShaderAllocator::~ShaderAllocator (void)
    239 {
    240 	for (std::map<glu::ShaderType, glu::Shader*>::iterator shaderIter = m_shaders.begin(); shaderIter != m_shaders.end(); shaderIter++)
    241 		delete shaderIter->second;
    242 	m_shaders.clear();
    243 }
    244 
    245 bool ShaderAllocator::hasShader (const glu::ShaderType shaderType)
    246 {
    247 	if (m_shaders.find(shaderType) != m_shaders.end())
    248 		return true;
    249 	else
    250 		return false;
    251 }
    252 
    253 glu::Shader& ShaderAllocator::createShader (const glu::ShaderType shaderType)
    254 {
    255 	DE_ASSERT(!this->hasShader(shaderType));
    256 
    257 	glu::Shader* const	shader	= new glu::Shader(m_context, shaderType);
    258 
    259 	m_shaders[shaderType] = shader;
    260 	this->setSource(shaderType);
    261 
    262 	return *shader;
    263 }
    264 
    265 void ShaderAllocator::deleteShader (const glu::ShaderType shaderType)
    266 {
    267 	DE_ASSERT(this->hasShader(shaderType));
    268 
    269 	delete m_shaders[shaderType];
    270 	m_shaders.erase(shaderType);
    271 }
    272 
    273 void ShaderAllocator::setSource (const glu::ShaderType shaderType)
    274 {
    275 	DE_ASSERT(this->hasShader(shaderType));
    276 	DE_ASSERT(!m_srcGen.finished(shaderType));
    277 
    278 	const std::string	source	= m_srcGen.next(shaderType);
    279 	const char* const	cSource	= source.c_str();
    280 
    281 	m_shaders[shaderType]->setSources(1, &cSource, 0);
    282 }
    283 
    284 // Logging utilities
    285 
    286 void logShader (TestLog& log, glu::RenderContext& renderCtx, glu::Shader& shader)
    287 {
    288 	glu::ShaderInfo info;
    289 	queryShaderInfo(renderCtx, shader.getShader(), info);
    290 
    291 	log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog);
    292 }
    293 
    294 void logProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, ShaderAllocator& shaders)
    295 {
    296 	log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
    297 
    298 	for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++)
    299 	{
    300 		const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt;
    301 
    302 		if (shaders.hasShader(shaderType))
    303 			logShader(log, renderCtx, shaders.get(shaderType));
    304 	}
    305 
    306 	log << TestLog::EndShaderProgram;
    307 }
    308 
    309 void logVertexFragmentProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, glu::Shader& vertShader, glu::Shader& fragShader)
    310 {
    311 	DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT);
    312 
    313 	log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
    314 
    315 	logShader(log, renderCtx, vertShader);
    316 	logShader(log, renderCtx, fragShader);
    317 
    318 	log << TestLog::EndShaderProgram;
    319 }
    320 
    321 } // anonymous
    322 
    323 // Simple glCreateShader() case
    324 
    325 class CreateShaderCase : public ApiCase
    326 {
    327 public:
    328 	CreateShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    329 		: ApiCase		(context, name, desc)
    330 		, m_shaderType	(shaderType)
    331 	{
    332 	}
    333 
    334 	void test (void)
    335 	{
    336 		const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
    337 
    338 		TCU_CHECK(shaderObject != 0);
    339 
    340 		glDeleteShader(shaderObject);
    341 	}
    342 
    343 private:
    344 	const glu::ShaderType m_shaderType;
    345 };
    346 
    347 // Simple glCompileShader() case
    348 
    349 class CompileShaderCase : public ApiCase
    350 {
    351 public:
    352 	CompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    353 		: ApiCase		(context, name, desc)
    354 		, m_shaderType	(shaderType)
    355 	{
    356 	}
    357 
    358 	bool checkCompileStatus (const GLuint shaderObject)
    359 	{
    360 		GLint compileStatus = -1;
    361 		glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus);
    362 		GLU_CHECK();
    363 
    364 		return (compileStatus == GL_TRUE);
    365 	}
    366 
    367 	void test (void)
    368 	{
    369 		const char*		shaderSource	= getSimpleShaderSource(m_shaderType);
    370 		const GLuint	shaderObject	= glCreateShader(glu::getGLShaderType(m_shaderType));
    371 
    372 		TCU_CHECK(shaderObject != 0);
    373 
    374 		glShaderSource(shaderObject, 1, &shaderSource, 0);
    375 		glCompileShader(shaderObject);
    376 
    377 		TCU_CHECK(checkCompileStatus(shaderObject));
    378 
    379 		glDeleteShader(shaderObject);
    380 	}
    381 
    382 private:
    383 	const glu::ShaderType m_shaderType;
    384 };
    385 
    386 // Base class for simple program API tests
    387 
    388 class SimpleProgramCase : public ApiCase
    389 {
    390 public:
    391 	SimpleProgramCase (Context& context, const char* name, const char* desc)
    392 		: ApiCase 		(context, name, desc)
    393 		, m_vertShader	(0)
    394 		, m_fragShader	(0)
    395 		, m_program		(0)
    396 	{
    397 	}
    398 
    399 	virtual ~SimpleProgramCase (void)
    400 	{
    401 	}
    402 
    403 	virtual void compileShaders (void)
    404 	{
    405 		const char*		vertSource	= getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
    406 		const char*		fragSource	= getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
    407 
    408 		const GLuint	vertShader	= glCreateShader(GL_VERTEX_SHADER);
    409 		const GLuint	fragShader	= glCreateShader(GL_FRAGMENT_SHADER);
    410 
    411 		TCU_CHECK(vertShader != 0);
    412 		TCU_CHECK(fragShader != 0);
    413 
    414 		glShaderSource(vertShader, 1, &vertSource, 0);
    415 		glCompileShader(vertShader);
    416 
    417 		glShaderSource(fragShader, 1, &fragSource, 0);
    418 		glCompileShader(fragShader);
    419 
    420 		GLU_CHECK();
    421 
    422 		m_vertShader = vertShader;
    423 		m_fragShader = fragShader;
    424 	}
    425 
    426 	void linkProgram (void)
    427 	{
    428 		const GLuint program = glCreateProgram();
    429 
    430 		TCU_CHECK(program != 0);
    431 
    432 		glAttachShader(program, m_vertShader);
    433 		glAttachShader(program, m_fragShader);
    434 		GLU_CHECK();
    435 
    436 		glLinkProgram(program);
    437 
    438 		m_program = program;
    439 	}
    440 
    441 	void cleanup (void)
    442 	{
    443 		glDeleteShader(m_vertShader);
    444 		glDeleteShader(m_fragShader);
    445 		glDeleteProgram(m_program);
    446 	}
    447 
    448 protected:
    449 	GLuint	m_vertShader;
    450 	GLuint	m_fragShader;
    451 	GLuint	m_program;
    452 };
    453 
    454 // glDeleteShader() case
    455 
    456 class DeleteShaderCase : public SimpleProgramCase
    457 {
    458 public:
    459 	DeleteShaderCase (Context& context, const char* name, const char* desc)
    460 		: SimpleProgramCase (context, name, desc)
    461 	{
    462 	}
    463 
    464 	bool checkDeleteStatus(GLuint shader)
    465 	{
    466 		GLint deleteStatus = -1;
    467 		glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus);
    468 		GLU_CHECK();
    469 
    470 		return (deleteStatus == GL_TRUE);
    471 	}
    472 
    473 	void deleteShaders (void)
    474 	{
    475 		glDeleteShader(m_vertShader);
    476 		glDeleteShader(m_fragShader);
    477 		GLU_CHECK();
    478 	}
    479 
    480 	void test (void)
    481 	{
    482 		compileShaders();
    483 		linkProgram();
    484 		GLU_CHECK();
    485 
    486 		deleteShaders();
    487 
    488 		TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader));
    489 
    490 		glDeleteProgram(m_program);
    491 
    492 		TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader)));
    493 	}
    494 };
    495 
    496 // Simple glLinkProgram() case
    497 
    498 class LinkVertexFragmentCase : public SimpleProgramCase
    499 {
    500 public:
    501 	LinkVertexFragmentCase (Context& context, const char* name, const char* desc)
    502 		: SimpleProgramCase (context, name, desc)
    503 	{
    504 	}
    505 
    506 	bool checkLinkStatus (const GLuint programObject)
    507 	{
    508 		GLint linkStatus = -1;
    509 		glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus);
    510 		GLU_CHECK();
    511 
    512 		return (linkStatus == GL_TRUE);
    513 	}
    514 
    515 	void test (void)
    516 	{
    517 		compileShaders();
    518 		linkProgram();
    519 
    520 		GLU_CHECK_MSG("Linking failed.");
    521 		TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE.");
    522 
    523 		cleanup();
    524 	}
    525 };
    526 
    527 class ShaderSourceReplaceCase : public ApiCase
    528 {
    529 public:
    530 	ShaderSourceReplaceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    531 		: ApiCase		(context, name, desc)
    532 		, m_shaderType	(shaderType)
    533 	{
    534 	}
    535 
    536 	std::string generateFirstSource (void)
    537 	{
    538 		return getSimpleShaderSource(m_shaderType);
    539 	}
    540 
    541 	std::string generateSecondSource (void)
    542 	{
    543 		std::string str;
    544 
    545 		str  = "#version 100\n";
    546 		str += "precision highp float;\n\n";
    547 
    548 		str += "void main()\n";
    549 		str += "{\n";
    550 		str += "	float variable = 1.0;\n";
    551 
    552 		if		(m_shaderType == glu::SHADERTYPE_VERTEX)	str += "	gl_Position = vec4(variable);\n";
    553 		else if	(m_shaderType == glu::SHADERTYPE_FRAGMENT)	str += "	gl_FragColor = vec4(variable);\n";
    554 
    555 		str += "}\n";
    556 
    557 		return str;
    558 	}
    559 
    560 	GLint getSourceLength (glu::Shader& shader)
    561 	{
    562 		GLint sourceLength = 0;
    563 		glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength);
    564 		GLU_CHECK();
    565 
    566 		return sourceLength;
    567 	}
    568 
    569 	std::string readSource (glu::Shader& shader)
    570 	{
    571 		const GLint			sourceLength	= getSourceLength(shader);
    572 		std::vector<char>	sourceBuffer	(sourceLength + 1);
    573 
    574 		glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]);
    575 
    576 		return std::string(&sourceBuffer[0]);
    577 	}
    578 
    579 	void verifyShaderSourceReplaced (glu::Shader& shader, const std::string& firstSource, const std::string& secondSource)
    580 	{
    581 		TestLog&			log		= m_testCtx.getLog();
    582 		const std::string	result	= readSource(shader);
    583 
    584 		if (result == firstSource)
    585 		{
    586 			log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage;
    587 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced");
    588 		}
    589 		else if (result != secondSource)
    590 		{
    591 			log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage;
    592 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source");
    593 		}
    594 	}
    595 
    596 	void test (void)
    597 	{
    598 		TestLog&			log				= m_testCtx.getLog();
    599 
    600 		glu::Shader			shader			(m_context.getRenderContext(), m_shaderType);
    601 
    602 		const std::string	firstSourceStr	= generateFirstSource();
    603 		const std::string	secondSourceStr	= generateSecondSource();
    604 
    605 		const char*			firstSource		= firstSourceStr.c_str();
    606 		const char*			secondSource	= secondSourceStr.c_str();
    607 
    608 		log << TestLog::Message << "Setting shader source." << TestLog::EndMessage;
    609 
    610 		shader.setSources(1, &firstSource, 0);
    611 		GLU_CHECK();
    612 
    613 		log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage;
    614 
    615 		shader.setSources(1, &secondSource, 0);
    616 		GLU_CHECK();
    617 
    618 		verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr);
    619 	}
    620 
    621 private:
    622 	glu::ShaderType	m_shaderType;
    623 };
    624 
    625 // glShaderSource() split source case
    626 
    627 class ShaderSourceSplitCase : public ApiCase
    628 {
    629 public:
    630 	ShaderSourceSplitCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType, const int numSlices, const deUint32 flags = 0)
    631 		: ApiCase			(context, name, desc)
    632 		, m_rnd				(deStringHash(getName()) ^ 0x4fb2337d)
    633 		, m_shaderType		(shaderType)
    634 		, m_numSlices		(numSlices)
    635 		, m_explicitLengths	((flags & CASE_EXPLICIT_SOURCE_LENGTHS)	!= 0)
    636 		, m_randomNullTerm	((flags & CASE_RANDOM_NULL_TERMINATED)	!= 0)
    637 	{
    638 		DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
    639 	}
    640 
    641 	virtual ~ShaderSourceSplitCase (void)
    642 	{
    643 	}
    644 
    645 	std::string generateFullSource (void)
    646 	{
    647 		std::string str;
    648 
    649 		str  = "#version 100\n";
    650 		str += "precision highp float;\n\n";
    651 
    652 		str += "void main()\n";
    653 		str += "{\n";
    654 		str += "	float variable = 1.0;\n";
    655 
    656 		if		(m_shaderType == glu::SHADERTYPE_VERTEX)	str += "	gl_Position = vec4(variable);\n";
    657 		else if	(m_shaderType == glu::SHADERTYPE_FRAGMENT)	str += "	gl_FragColor = vec4(variable);\n";
    658 
    659 		str += "}\n";
    660 
    661 		return str;
    662 	}
    663 
    664 	void insertRandomNullTermStrings (ShaderSources& sources)
    665 	{
    666 		const int			numInserts	= de::max(m_numSlices >> 2, 1);
    667 		std::vector<int>	indices		(sources.strings.size(), 0);
    668 
    669 		DE_ASSERT(sources.lengths.size() > 0);
    670 		DE_ASSERT(sources.lengths.size() == sources.strings.size());
    671 
    672 		for (int i = 0; i < (int)sources.strings.size(); i++)
    673 			indices[i] = i;
    674 
    675 		m_rnd.shuffle(indices.begin(), indices.end());
    676 
    677 		for (int i = 0; i < numInserts; i++)
    678 		{
    679 			const int			ndx				= indices[i];
    680 			const int			unpaddedLength	= sources.lengths[ndx];
    681 			const std::string	unpaddedString	= sources.strings[ndx].substr(0, unpaddedLength);
    682 
    683 			sources.strings[ndx] = unpaddedString;
    684 			sources.lengths[ndx] = m_rnd.getInt(-10, -1);
    685 		}
    686 	}
    687 
    688 	void generateSources (ShaderSources& sources)
    689 	{
    690 		const size_t	paddingLength	= (m_explicitLengths ? 10 : 0);
    691 		std::string		str				= generateFullSource();
    692 
    693 		sliceSourceString(str, sources, m_numSlices, paddingLength);
    694 
    695 		if (m_randomNullTerm)
    696 			insertRandomNullTermStrings(sources);
    697 	}
    698 
    699 	void buildProgram (glu::Shader& shader)
    700 	{
    701 		TestLog&				log					= m_testCtx.getLog();
    702 		glu::RenderContext&		renderCtx			= m_context.getRenderContext();
    703 
    704 		const glu::ShaderType	supportShaderType	= (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT);
    705 		const char*				supportShaderSource	= getSimpleShaderSource(supportShaderType);
    706 		glu::Shader				supportShader		(renderCtx, supportShaderType);
    707 
    708 		glu::Program			program				(renderCtx);
    709 
    710 		supportShader.setSources(1, &supportShaderSource, 0);
    711 		supportShader.compile();
    712 
    713 		program.attachShader(shader.getShader());
    714 		program.attachShader(supportShader.getShader());
    715 
    716 		program.link();
    717 
    718 		if (m_shaderType == glu::SHADERTYPE_VERTEX)
    719 			logVertexFragmentProgram(log, renderCtx, program, shader, supportShader);
    720 		else
    721 			logVertexFragmentProgram(log, renderCtx, program, supportShader, shader);
    722 	}
    723 
    724 	void test (void)
    725 	{
    726 		TestLog&			log			= m_testCtx.getLog();
    727 		glu::RenderContext&	renderCtx	= m_context.getRenderContext();
    728 
    729 		ShaderSources		sources;
    730 		glu::Shader			shader		(renderCtx, m_shaderType);
    731 
    732 		generateSources(sources);
    733 		setShaderSources(shader, sources);
    734 		shader.compile();
    735 
    736 		buildProgram(shader);
    737 
    738 		if (!shader.getCompileStatus())
    739 		{
    740 			log << TestLog::Message << "Compilation failed." << TestLog::EndMessage;
    741 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
    742 		}
    743 	}
    744 
    745 private:
    746 	de::Random		m_rnd;
    747 
    748 	glu::ShaderType	m_shaderType;
    749 	const int		m_numSlices;
    750 
    751 	const bool		m_explicitLengths;
    752 	const bool		m_randomNullTerm;
    753 };
    754 
    755 // Base class for program state persistence cases
    756 
    757 class ProgramStateCase : public ApiCase
    758 {
    759 public:
    760 					ProgramStateCase	(Context& context, const char* name, const char* desc, glu::ShaderType shaderType);
    761 	virtual			~ProgramStateCase	(void)	{}
    762 
    763 	void			buildProgram		(glu::Program& program, ShaderAllocator& shaders);
    764 	void			verify				(glu::Program& program, const glu::ProgramInfo& reference);
    765 
    766 	void			test				(void);
    767 
    768 	virtual void	executeForProgram	(glu::Program& program, ShaderAllocator& shaders)	= 0;
    769 
    770 protected:
    771 	de::Random					m_rnd;
    772 	const glu::ShaderType		m_shaderType;
    773 };
    774 
    775 ProgramStateCase::ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    776 	: ApiCase		(context, name, desc)
    777 	, m_rnd			(deStringHash(name) ^ 0x713de0ca)
    778 	, m_shaderType	(shaderType)
    779 {
    780 	DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
    781 }
    782 
    783 void ProgramStateCase::buildProgram (glu::Program& program, ShaderAllocator& shaders)
    784 {
    785 	TestLog&		log			= m_testCtx.getLog();
    786 
    787 	glu::Shader&	vertShader	= shaders.createShader(glu::SHADERTYPE_VERTEX);
    788 	glu::Shader&	fragShader	= shaders.createShader(glu::SHADERTYPE_FRAGMENT);
    789 
    790 	vertShader.compile();
    791 	fragShader.compile();
    792 
    793 	program.attachShader(vertShader.getShader());
    794 	program.attachShader(fragShader.getShader());
    795 	program.link();
    796 
    797 	logProgram(log, m_context.getRenderContext(), program, shaders);
    798 }
    799 
    800 void ProgramStateCase::verify (glu::Program& program, const glu::ProgramInfo& reference)
    801 {
    802 	TestLog&				log			= m_testCtx.getLog();
    803 	const glu::ProgramInfo&	programInfo	= program.getInfo();
    804 
    805 	if (!programInfo.linkOk)
    806 	{
    807 		log << TestLog::Message << "Fail, link status may only change as a result of linking or loading a program binary." << TestLog::EndMessage;
    808 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed");
    809 	}
    810 
    811 	if (programInfo.linkTimeUs != reference.linkTimeUs)
    812 	{
    813 		log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage;
    814 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed");
    815 	}
    816 
    817 	if (programInfo.infoLog != reference.infoLog)
    818 	{
    819 		log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage;
    820 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed");
    821 	}
    822 }
    823 
    824 void ProgramStateCase::test (void)
    825 {
    826 	TestLog&				log			= m_testCtx.getLog();
    827 	glu::RenderContext&		renderCtx	= m_context.getRenderContext();
    828 
    829 	ConstantShaderGenerator	sourceGen	(m_rnd);
    830 
    831 	ShaderAllocator			shaders		(renderCtx, sourceGen);
    832 	glu::Program			program		(renderCtx);
    833 
    834 	buildProgram(program, shaders);
    835 
    836 	if (program.getLinkStatus())
    837 	{
    838 		glu::ProgramInfo programInfo = program.getInfo();
    839 
    840 		executeForProgram(program, shaders);
    841 
    842 		verify(program, programInfo);
    843 
    844 		logProgram(log, renderCtx, program, shaders);
    845 	}
    846 	else
    847 	{
    848 		log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
    849 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
    850 	}
    851 }
    852 
    853 // Program state case utilities
    854 
    855 namespace
    856 {
    857 
    858 template<class T>
    859 void addProgramStateCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc)
    860 {
    861 	for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
    862 	{
    863 		const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
    864 		const std::string		shaderTypeName	= getShaderTypeName(shaderType);
    865 
    866 		const std::string		caseName		= name + "_" + shaderTypeName;
    867 		const std::string		caseDesc		= "Build program, " + desc + ", for " + shaderTypeName + " shader.";
    868 
    869 		group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
    870 	}
    871 }
    872 
    873 } // anonymous
    874 
    875 // Specialized program state cases
    876 
    877 class ProgramStateDetachShaderCase : public ProgramStateCase
    878 {
    879 public:
    880 	ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    881 		: ProgramStateCase (context, name, desc, shaderType)
    882 	{
    883 	}
    884 
    885 	virtual ~ProgramStateDetachShaderCase (void)
    886 	{
    887 	}
    888 
    889 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    890 	{
    891 		TestLog&		log			= m_testCtx.getLog();
    892 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    893 
    894 		log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    895 		program.detachShader(caseShader.getShader());
    896 	}
    897 };
    898 
    899 class ProgramStateReattachShaderCase : public ProgramStateCase
    900 {
    901 public:
    902 	ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    903 		: ProgramStateCase (context, name, desc, shaderType)
    904 	{
    905 	}
    906 
    907 	virtual ~ProgramStateReattachShaderCase (void)
    908 	{
    909 	}
    910 
    911 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    912 	{
    913 		TestLog&		log			= m_testCtx.getLog();
    914 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    915 
    916 		log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    917 		program.detachShader(caseShader.getShader());
    918 		program.attachShader(caseShader.getShader());
    919 	}
    920 };
    921 
    922 class ProgramStateDeleteShaderCase : public ProgramStateCase
    923 {
    924 public:
    925 	ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    926 		: ProgramStateCase (context, name, desc, shaderType)
    927 	{
    928 	}
    929 
    930 	virtual ~ProgramStateDeleteShaderCase (void)
    931 	{
    932 	}
    933 
    934 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    935 	{
    936 		TestLog&		log			= m_testCtx.getLog();
    937 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    938 
    939 		log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    940 		program.detachShader(caseShader.getShader());
    941 		shaders.deleteShader(m_shaderType);
    942 	}
    943 };
    944 
    945 class ProgramStateReplaceShaderCase : public ProgramStateCase
    946 {
    947 public:
    948 	ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    949 		: ProgramStateCase (context, name, desc, shaderType)
    950 	{
    951 	}
    952 
    953 	virtual ~ProgramStateReplaceShaderCase (void)
    954 	{
    955 	}
    956 
    957 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    958 	{
    959 		TestLog&		log			= m_testCtx.getLog();
    960 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    961 
    962 		log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    963 		program.detachShader(caseShader.getShader());
    964 		shaders.deleteShader(m_shaderType);
    965 		program.attachShader(shaders.createShader(m_shaderType).getShader());
    966 	}
    967 };
    968 
    969 class ProgramStateRecompileShaderCase : public ProgramStateCase
    970 {
    971 public:
    972 	ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    973 		: ProgramStateCase (context, name, desc, shaderType)
    974 	{
    975 	}
    976 
    977 	virtual ~ProgramStateRecompileShaderCase (void)
    978 	{
    979 	}
    980 
    981 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    982 	{
    983 		TestLog&		log			= m_testCtx.getLog();
    984 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    985 
    986 		log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    987 		caseShader.compile();
    988 		DE_UNREF(program);
    989 	}
    990 };
    991 
    992 class ProgramStateReplaceSourceCase : public ProgramStateCase
    993 {
    994 public:
    995 	ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    996 		: ProgramStateCase (context, name, desc, shaderType)
    997 	{
    998 	}
    999 
   1000 	virtual ~ProgramStateReplaceSourceCase (void)
   1001 	{
   1002 	}
   1003 
   1004 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1005 	{
   1006 		TestLog&		log			= m_testCtx.getLog();
   1007 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1008 
   1009 		log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage;
   1010 		shaders.setSource(m_shaderType);
   1011 		caseShader.compile();
   1012 		DE_UNREF(program);
   1013 	}
   1014 };
   1015 
   1016 // Test group
   1017 
   1018 ShaderApiTests::ShaderApiTests (Context& context)
   1019 	: TestCaseGroup(context, "shader_api", "Shader API Cases")
   1020 {
   1021 }
   1022 
   1023 ShaderApiTests::~ShaderApiTests (void)
   1024 {
   1025 }
   1026 
   1027 void ShaderApiTests::init (void)
   1028 {
   1029 	// create and delete shaders
   1030 	{
   1031 		TestCaseGroup* createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests");
   1032 		addChild(createDeleteGroup);
   1033 
   1034 		createDeleteGroup->addChild(new CreateShaderCase(m_context,	"create_vertex_shader",		"Create vertex shader object",		glu::SHADERTYPE_VERTEX));
   1035 		createDeleteGroup->addChild(new CreateShaderCase(m_context,	"create_fragment_shader",	"Create fragment shader object",	glu::SHADERTYPE_FRAGMENT));
   1036 
   1037 		createDeleteGroup->addChild(new DeleteShaderCase(m_context,	"delete_vertex_fragment",	"Delete vertex shader and fragment shader"));
   1038 	}
   1039 
   1040 	// compile and link
   1041 	{
   1042 		TestCaseGroup* compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests");
   1043 		addChild(compileLinkGroup);
   1044 
   1045 		compileLinkGroup->addChild(new CompileShaderCase(m_context,	"compile_vertex_shader",	"Compile vertex shader",	glu::SHADERTYPE_VERTEX));
   1046 		compileLinkGroup->addChild(new CompileShaderCase(m_context,	"compile_fragment_shader",	"Compile fragment shader",	glu::SHADERTYPE_FRAGMENT));
   1047 
   1048 		compileLinkGroup->addChild(new LinkVertexFragmentCase(m_context,	"link_vertex_fragment",	"Link vertex and fragment shaders"));
   1049 	}
   1050 
   1051 	// shader source
   1052 	{
   1053 		TestCaseGroup* shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests");
   1054 		addChild(shaderSourceGroup);
   1055 
   1056 		for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
   1057 		{
   1058 			const glu::ShaderType	shaderType	= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
   1059 
   1060 			const std::string		caseName	= std::string("replace_source") + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
   1061 			const std::string		caseDesc	= std::string("Replace source code of ") + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "fragment" : "vertex") + " shader.";
   1062 
   1063 			shaderSourceGroup->addChild(new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType));
   1064 		}
   1065 
   1066 		for (int stringLengthsInt	= 0; stringLengthsInt < 3; stringLengthsInt++)
   1067 		for (int caseNdx = 1; caseNdx <= 3; caseNdx++)
   1068 		for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
   1069 		{
   1070 			const int				numSlices		= 1 << caseNdx;
   1071 			const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
   1072 
   1073 			const bool				explicitLengths	= (stringLengthsInt != 0);
   1074 			const bool				randomNullTerm	= (stringLengthsInt == 2);
   1075 
   1076 			const deUint32			flags			= (explicitLengths	? CASE_EXPLICIT_SOURCE_LENGTHS	: 0)
   1077 													| (randomNullTerm	? CASE_RANDOM_NULL_TERMINATED	: 0);
   1078 
   1079 			const std::string		caseName		= "split_source_"
   1080 													+ de::toString(numSlices)
   1081 													+ (randomNullTerm ? "_random_negative_length" : (explicitLengths ? "_specify_lengths" : "_null_terminated"))
   1082 													+ ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
   1083 
   1084 			const std::string		caseDesc		= std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex")
   1085 													+ " shader source split into "
   1086 													+ de::toString(numSlices)
   1087 													+ " pieces"
   1088 													+ (explicitLengths ? ", using explicitly specified string lengths" : "")
   1089 													+ (randomNullTerm ? " with random negative length values" : "");
   1090 
   1091 			shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType, numSlices, flags));
   1092 		}
   1093 	}
   1094 
   1095 	// link status and infolog
   1096 	{
   1097 		TestCaseGroup* linkStatusGroup = new TestCaseGroup(m_context, "program_state", "Program state persistence tests");
   1098 		addChild(linkStatusGroup);
   1099 
   1100 		addProgramStateCase<ProgramStateDetachShaderCase>		(linkStatusGroup,	m_context,	"detach_shader",	"detach shader");
   1101 		addProgramStateCase<ProgramStateReattachShaderCase>		(linkStatusGroup,	m_context,	"reattach_shader",	"reattach shader");
   1102 		addProgramStateCase<ProgramStateDeleteShaderCase>		(linkStatusGroup,	m_context,	"delete_shader",	"delete shader");
   1103 		addProgramStateCase<ProgramStateReplaceShaderCase>		(linkStatusGroup,	m_context,	"replace_shader",	"replace shader object");
   1104 		addProgramStateCase<ProgramStateRecompileShaderCase>	(linkStatusGroup,	m_context,	"recompile_shader",	"recompile shader");
   1105 		addProgramStateCase<ProgramStateReplaceSourceCase>		(linkStatusGroup,	m_context,	"replace_source",	"replace shader source");
   1106 	}
   1107 }
   1108 
   1109 } // Functional
   1110 } // gles2
   1111 } // deqp
   1112