Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.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 "es3fShaderApiTests.hpp"
     25 #include "es3fApiCase.hpp"
     26 #include "tcuTestLog.hpp"
     27 
     28 #include "gluRenderContext.hpp"
     29 #include "gluShaderProgram.hpp"
     30 #include "gluShaderUtil.hpp"
     31 #include "gluDrawUtil.hpp"
     32 #include "gluContextInfo.hpp"
     33 #include "gluCallLogWrapper.hpp"
     34 
     35 #include "glwFunctions.hpp"
     36 #include "glwDefs.hpp"
     37 #include "glwEnums.hpp"
     38 
     39 #include "deString.h"
     40 
     41 #include "deRandom.hpp"
     42 #include "deStringUtil.hpp"
     43 
     44 #include <string>
     45 #include <sstream>
     46 #include <vector>
     47 #include <map>
     48 
     49 using namespace glw; // GL types
     50 
     51 namespace deqp
     52 {
     53 namespace gles3
     54 {
     55 namespace Functional
     56 {
     57 
     58 using tcu::TestLog;
     59 
     60 namespace
     61 {
     62 
     63 enum ShaderSourceCaseFlags
     64 {
     65 	CASE_EXPLICIT_SOURCE_LENGTHS	= 1,
     66 	CASE_RANDOM_NULL_TERMINATED		= 2
     67 };
     68 
     69 struct ShaderSources
     70 {
     71 	std::vector<std::string>	strings;
     72 	std::vector<int>			lengths;
     73 };
     74 
     75 // Simple shaders
     76 
     77 const char* getSimpleShaderSource (const glu::ShaderType shaderType)
     78 {
     79 	const char* simpleVertexShaderSource =
     80 		"#version 300 es\n"
     81 		"void main (void)\n"
     82 		"{\n"
     83 		"	gl_Position = vec4(0.0);\n"
     84 		"}\n";
     85 
     86 	const char* simpleFragmentShaderSource =
     87 		"#version 300 es\n"
     88 		"layout(location = 0) out mediump vec4 o_fragColor;\n"
     89 		"void main (void)\n"
     90 		"{\n"
     91 		"	o_fragColor = vec4(0.0);\n"
     92 		"}\n";
     93 
     94 	switch (shaderType)
     95 	{
     96 		case glu::SHADERTYPE_VERTEX:
     97 			return simpleVertexShaderSource;
     98 		case glu::SHADERTYPE_FRAGMENT:
     99 			return simpleFragmentShaderSource;
    100 		default:
    101 			DE_ASSERT(DE_FALSE);
    102 	}
    103 
    104 	return 0;
    105 }
    106 
    107 void setShaderSources (glu::Shader& shader, const ShaderSources& sources)
    108 {
    109 	std::vector<const char*> cStrings (sources.strings.size(), 0);
    110 
    111 	for (size_t ndx = 0; ndx < sources.strings.size(); ndx++)
    112 		cStrings[ndx] = sources.strings[ndx].c_str();
    113 
    114 	if (sources.lengths.size() > 0)
    115 		shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]);
    116 	else
    117 		shader.setSources((int)cStrings.size(), &cStrings[0], 0);
    118 }
    119 
    120 void sliceSourceString (const std::string& in, ShaderSources& out, const int numSlices, const size_t paddingLength = 0)
    121 {
    122 	DE_ASSERT(numSlices > 0);
    123 
    124 	const size_t		sliceSize			= in.length() / numSlices;
    125 	const size_t		sliceSizeRemainder	= in.length() - (sliceSize * numSlices);
    126 	const std::string	padding				(paddingLength, 'E');
    127 
    128 	for (int ndx = 0; ndx < numSlices; ndx++)
    129 	{
    130 		out.strings.push_back(in.substr(ndx * sliceSize, sliceSize) + padding);
    131 
    132 		if (paddingLength > 0)
    133 			out.lengths.push_back((int)sliceSize);
    134 	}
    135 
    136 	if (sliceSizeRemainder > 0)
    137 	{
    138 		const std::string	lastString			= in.substr(numSlices * sliceSize);
    139 		const int			lastStringLength	= (int)lastString.length();
    140 
    141 		out.strings.push_back(lastString + padding);
    142 
    143 		if (paddingLength > 0)
    144 			out.lengths.push_back(lastStringLength);
    145 	}
    146 }
    147 
    148 void queryShaderInfo (glu::RenderContext& renderCtx, deUint32 shader, glu::ShaderInfo& info)
    149 {
    150 	const glw::Functions& gl = renderCtx.getFunctions();
    151 
    152 	info.compileOk		= false;
    153 	info.compileTimeUs	= 0;
    154 	info.infoLog.clear();
    155 
    156 	// Query source, status & log.
    157 	{
    158 		int	compileStatus	= 0;
    159 		int sourceLen		= 0;
    160 		int	infoLogLen		= 0;
    161 		int	unusedLen;
    162 
    163 		gl.getShaderiv(shader, GL_COMPILE_STATUS,			&compileStatus);
    164 		gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH,	&sourceLen);
    165 		gl.getShaderiv(shader, GL_INFO_LOG_LENGTH,		&infoLogLen);
    166 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
    167 
    168 		info.compileOk = compileStatus != GL_FALSE;
    169 
    170 		if (sourceLen > 0)
    171 		{
    172 			std::vector<char> source(sourceLen);
    173 			gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]);
    174 			info.source = std::string(&source[0], sourceLen);
    175 		}
    176 
    177 		if (infoLogLen > 0)
    178 		{
    179 			std::vector<char> infoLog(infoLogLen);
    180 			gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
    181 			info.infoLog = std::string(&infoLog[0], infoLogLen);
    182 		}
    183 	}
    184 }
    185 
    186 // Draw test quad
    187 
    188 void drawWithProgram (glu::RenderContext& renderCtx, deUint32 program)
    189 {
    190 	const glw::Functions& gl = renderCtx.getFunctions();
    191 
    192 	const float position[] =
    193 	{
    194 		-1.0f, -1.0f,  0.0f, 1.0f,
    195 		-1.0f, +1.0f,  0.0f, 1.0f,
    196 		+1.0f, -1.0f,  0.0f, 1.0f,
    197 		+1.0f, +1.0f,  0.0f, 1.0f
    198 	};
    199 	const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
    200 
    201 	gl.useProgram(program);
    202 
    203 	{
    204 		glu::VertexArrayBinding vertexArrays[] =
    205 		{
    206 			glu::va::Float("a_position",	4, 4, 0, &position[0])
    207 		};
    208 		glu::draw(renderCtx, program, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
    209 	}
    210 
    211 	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw test quad");
    212 }
    213 
    214 // Shader source generator
    215 
    216 class SourceGenerator
    217 {
    218 public:
    219 	virtual				~SourceGenerator	(void)	{}
    220 
    221 	virtual std::string	next				(const glu::ShaderType shaderType)			= 0;
    222 	virtual bool		finished			(const glu::ShaderType shaderType) const	= 0;
    223 };
    224 
    225 class ConstantShaderGenerator : public SourceGenerator
    226 {
    227 public:
    228 				ConstantShaderGenerator		(de::Random& rnd)	: m_rnd(rnd)	{}
    229 				~ConstantShaderGenerator	(void)								{}
    230 
    231 	bool		finished					(const glu::ShaderType shaderType) const	{ DE_UNREF(shaderType); return false; }
    232 
    233 	std::string	next						(const glu::ShaderType shaderType);
    234 
    235 private:
    236 	de::Random	m_rnd;
    237 };
    238 
    239 std::string ConstantShaderGenerator::next (const glu::ShaderType shaderType)
    240 {
    241 	DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
    242 
    243 	const float			value		= m_rnd.getFloat(0.0f, 1.0f);
    244 	const std::string	valueString	= de::toString(value);
    245 	const std::string	outputName	= (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "o_fragColor";
    246 
    247 	std::ostringstream	out;
    248 
    249 	out << "#version 300 es\n";
    250 
    251 	if (shaderType == glu::SHADERTYPE_FRAGMENT)
    252 		out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
    253 
    254 	out << "void main (void)\n";
    255 	out << "{\n";
    256 	out << "	" << outputName << " = vec4(" << valueString << ");\n";
    257 	out << "}\n";
    258 
    259 	return out.str();
    260 }
    261 
    262 // Shader allocation utility
    263 
    264 class ShaderAllocator
    265 {
    266 public:
    267 					ShaderAllocator		(glu::RenderContext& context, SourceGenerator& generator);
    268 					~ShaderAllocator	(void);
    269 
    270 	bool			hasShader			(const glu::ShaderType shaderType);
    271 
    272 	void			setSource			(const glu::ShaderType shaderType);
    273 
    274 	glu::Shader&	createShader		(const glu::ShaderType shaderType);
    275 	void			deleteShader		(const glu::ShaderType shaderType);
    276 
    277 	glu::Shader&	get					(const glu::ShaderType shaderType)	{ DE_ASSERT(hasShader(shaderType)); return *m_shaders[shaderType]; }
    278 
    279 private:
    280 	const glu::RenderContext&				m_context;
    281 	SourceGenerator&						m_srcGen;
    282 	std::map<glu::ShaderType, glu::Shader*>	m_shaders;
    283 };
    284 
    285 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator)
    286 	: m_context	(context)
    287 	, m_srcGen	(generator)
    288 {
    289 }
    290 
    291 ShaderAllocator::~ShaderAllocator (void)
    292 {
    293 	for (std::map<glu::ShaderType, glu::Shader*>::iterator shaderIter = m_shaders.begin(); shaderIter != m_shaders.end(); shaderIter++)
    294 		delete shaderIter->second;
    295 	m_shaders.clear();
    296 }
    297 
    298 bool ShaderAllocator::hasShader (const glu::ShaderType shaderType)
    299 {
    300 	if (m_shaders.find(shaderType) != m_shaders.end())
    301 		return true;
    302 	else
    303 		return false;
    304 }
    305 
    306 glu::Shader& ShaderAllocator::createShader (const glu::ShaderType shaderType)
    307 {
    308 	DE_ASSERT(!this->hasShader(shaderType));
    309 
    310 	glu::Shader* const	shader	= new glu::Shader(m_context, shaderType);
    311 
    312 	m_shaders[shaderType] = shader;
    313 	this->setSource(shaderType);
    314 
    315 	return *shader;
    316 }
    317 
    318 void ShaderAllocator::deleteShader (const glu::ShaderType shaderType)
    319 {
    320 	DE_ASSERT(this->hasShader(shaderType));
    321 
    322 	delete m_shaders[shaderType];
    323 	m_shaders.erase(shaderType);
    324 }
    325 
    326 void ShaderAllocator::setSource (const glu::ShaderType shaderType)
    327 {
    328 	DE_ASSERT(this->hasShader(shaderType));
    329 	DE_ASSERT(!m_srcGen.finished(shaderType));
    330 
    331 	const std::string	source	= m_srcGen.next(shaderType);
    332 	const char* const	cSource	= source.c_str();
    333 
    334 	m_shaders[shaderType]->setSources(1, &cSource, 0);
    335 }
    336 
    337 // Logging utilities
    338 
    339 void logShader (TestLog& log, glu::RenderContext& renderCtx, glu::Shader& shader)
    340 {
    341 	glu::ShaderInfo info;
    342 
    343 	queryShaderInfo(renderCtx, shader.getShader(), info);
    344 
    345 	log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog);
    346 }
    347 
    348 void logProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, ShaderAllocator& shaders)
    349 {
    350 	log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
    351 
    352 	for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++)
    353 	{
    354 		const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt;
    355 
    356 		if (shaders.hasShader(shaderType))
    357 			logShader(log, renderCtx, shaders.get(shaderType));
    358 	}
    359 
    360 	log << TestLog::EndShaderProgram;
    361 }
    362 
    363 void logVertexFragmentProgram (TestLog& log, glu::RenderContext& renderCtx, glu::Program& program, glu::Shader& vertShader, glu::Shader& fragShader)
    364 {
    365 	DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT);
    366 
    367 	log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
    368 
    369 	logShader(log, renderCtx, vertShader);
    370 	logShader(log, renderCtx, fragShader);
    371 
    372 	log << TestLog::EndShaderProgram;
    373 }
    374 
    375 } // anonymous
    376 
    377 // Simple glCreateShader() case
    378 
    379 class CreateShaderCase : public ApiCase
    380 {
    381 public:
    382 	CreateShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    383 		: ApiCase		(context, name, desc)
    384 		, m_shaderType	(shaderType)
    385 	{
    386 	}
    387 
    388 	void test (void)
    389 	{
    390 		const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
    391 
    392 		TCU_CHECK(shaderObject != 0);
    393 
    394 		glDeleteShader(shaderObject);
    395 	}
    396 
    397 private:
    398 	const glu::ShaderType m_shaderType;
    399 };
    400 
    401 // Simple glCompileShader() case
    402 
    403 class CompileShaderCase : public ApiCase
    404 {
    405 public:
    406 	CompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    407 		: ApiCase		(context, name, desc)
    408 		, m_shaderType	(shaderType)
    409 	{
    410 	}
    411 
    412 	bool checkCompileStatus (const GLuint shaderObject)
    413 	{
    414 		GLint compileStatus = -1;
    415 		glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus);
    416 		GLU_CHECK();
    417 
    418 		return (compileStatus == GL_TRUE);
    419 	}
    420 
    421 	void test (void)
    422 	{
    423 		const char*		shaderSource	= getSimpleShaderSource(m_shaderType);
    424 		const GLuint	shaderObject	= glCreateShader(glu::getGLShaderType(m_shaderType));
    425 
    426 		TCU_CHECK(shaderObject != 0);
    427 
    428 		glShaderSource(shaderObject, 1, &shaderSource, 0);
    429 		glCompileShader(shaderObject);
    430 
    431 		TCU_CHECK(checkCompileStatus(shaderObject));
    432 
    433 		glDeleteShader(shaderObject);
    434 	}
    435 
    436 private:
    437 	const glu::ShaderType m_shaderType;
    438 };
    439 
    440 // Base class for simple program API tests
    441 
    442 class SimpleProgramCase : public ApiCase
    443 {
    444 public:
    445 	SimpleProgramCase (Context& context, const char* name, const char* desc)
    446 		: ApiCase 		(context, name, desc)
    447 		, m_vertShader	(0)
    448 		, m_fragShader	(0)
    449 		, m_program		(0)
    450 	{
    451 	}
    452 
    453 	virtual ~SimpleProgramCase (void)
    454 	{
    455 	}
    456 
    457 	virtual void compileShaders (void)
    458 	{
    459 		const char*		vertSource	= getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
    460 		const char*		fragSource	= getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
    461 
    462 		const GLuint	vertShader	= glCreateShader(GL_VERTEX_SHADER);
    463 		const GLuint	fragShader	= glCreateShader(GL_FRAGMENT_SHADER);
    464 
    465 		TCU_CHECK(vertShader != 0);
    466 		TCU_CHECK(fragShader != 0);
    467 
    468 		glShaderSource(vertShader, 1, &vertSource, 0);
    469 		glCompileShader(vertShader);
    470 
    471 		glShaderSource(fragShader, 1, &fragSource, 0);
    472 		glCompileShader(fragShader);
    473 
    474 		GLU_CHECK();
    475 
    476 		m_vertShader = vertShader;
    477 		m_fragShader = fragShader;
    478 	}
    479 
    480 	void linkProgram (void)
    481 	{
    482 		const GLuint program = glCreateProgram();
    483 
    484 		TCU_CHECK(program != 0);
    485 
    486 		glAttachShader(program, m_vertShader);
    487 		glAttachShader(program, m_fragShader);
    488 		GLU_CHECK();
    489 
    490 		glLinkProgram(program);
    491 
    492 		m_program = program;
    493 	}
    494 
    495 	void cleanup (void)
    496 	{
    497 		glDeleteShader(m_vertShader);
    498 		glDeleteShader(m_fragShader);
    499 		glDeleteProgram(m_program);
    500 	}
    501 
    502 protected:
    503 	GLuint	m_vertShader;
    504 	GLuint	m_fragShader;
    505 	GLuint	m_program;
    506 };
    507 
    508 // glDeleteShader() case
    509 
    510 class DeleteShaderCase : public SimpleProgramCase
    511 {
    512 public:
    513 	DeleteShaderCase (Context& context, const char* name, const char* desc)
    514 		: SimpleProgramCase (context, name, desc)
    515 	{
    516 	}
    517 
    518 	bool checkDeleteStatus(GLuint shader)
    519 	{
    520 		GLint deleteStatus = -1;
    521 		glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus);
    522 		GLU_CHECK();
    523 
    524 		return (deleteStatus == GL_TRUE);
    525 	}
    526 
    527 	void deleteShaders (void)
    528 	{
    529 		glDeleteShader(m_vertShader);
    530 		glDeleteShader(m_fragShader);
    531 		GLU_CHECK();
    532 	}
    533 
    534 	void test (void)
    535 	{
    536 		compileShaders();
    537 		linkProgram();
    538 		GLU_CHECK();
    539 
    540 		deleteShaders();
    541 
    542 		TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader));
    543 
    544 		glDeleteProgram(m_program);
    545 
    546 		TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader)));
    547 	}
    548 };
    549 
    550 // Simple glLinkProgram() case
    551 
    552 class LinkVertexFragmentCase : public SimpleProgramCase
    553 {
    554 public:
    555 	LinkVertexFragmentCase (Context& context, const char* name, const char* desc)
    556 		: SimpleProgramCase (context, name, desc)
    557 	{
    558 	}
    559 
    560 	bool checkLinkStatus (const GLuint programObject)
    561 	{
    562 		GLint linkStatus = -1;
    563 		glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus);
    564 		GLU_CHECK();
    565 
    566 		return (linkStatus == GL_TRUE);
    567 	}
    568 
    569 	void test (void)
    570 	{
    571 		compileShaders();
    572 		linkProgram();
    573 
    574 		GLU_CHECK_MSG("Linking failed.");
    575 		TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE.");
    576 
    577 		cleanup();
    578 	}
    579 };
    580 
    581 class ShaderSourceReplaceCase : public ApiCase
    582 {
    583 public:
    584 	ShaderSourceReplaceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    585 		: ApiCase		(context, name, desc)
    586 		, m_shaderType	(shaderType)
    587 	{
    588 	}
    589 
    590 	std::string generateFirstSource (void)
    591 	{
    592 		return getSimpleShaderSource(m_shaderType);
    593 	}
    594 
    595 	std::string generateSecondSource (void)
    596 	{
    597 		std::ostringstream out;
    598 
    599 		out << "#version 300 es\n";
    600 		out << "precision mediump float;\n";
    601 
    602 		if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
    603 			out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
    604 
    605 		out << "void main()\n";
    606 		out << "{\n";
    607 		out << "	float variable = 1.0f;\n";
    608 
    609 		if		(m_shaderType == glu::SHADERTYPE_VERTEX)	out << "	gl_Position = vec4(variable);\n";
    610 		else if	(m_shaderType == glu::SHADERTYPE_FRAGMENT)	out << "	o_fragColor = vec4(variable);\n";
    611 
    612 		out << "}\n";
    613 
    614 		return out.str();
    615 	}
    616 
    617 	GLint getSourceLength (glu::Shader& shader)
    618 	{
    619 		GLint sourceLength = 0;
    620 		glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength);
    621 		GLU_CHECK();
    622 
    623 		return sourceLength;
    624 	}
    625 
    626 	std::string readSource (glu::Shader& shader)
    627 	{
    628 		const GLint			sourceLength	= getSourceLength(shader);
    629 		std::vector<char>	sourceBuffer	(sourceLength + 1);
    630 
    631 		glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]);
    632 
    633 		return std::string(&sourceBuffer[0]);
    634 	}
    635 
    636 	void verifyShaderSourceReplaced (glu::Shader& shader, const std::string& firstSource, const std::string& secondSource)
    637 	{
    638 		TestLog&			log		= m_testCtx.getLog();
    639 		const std::string	result	= readSource(shader);
    640 
    641 		if (result == firstSource)
    642 		{
    643 			log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage;
    644 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced");
    645 		}
    646 		else if (result != secondSource)
    647 		{
    648 			log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage;
    649 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source");
    650 		}
    651 	}
    652 
    653 	void test (void)
    654 	{
    655 		TestLog&			log				= m_testCtx.getLog();
    656 
    657 		glu::Shader			shader			(m_context.getRenderContext(), m_shaderType);
    658 
    659 		const std::string	firstSourceStr	= generateFirstSource();
    660 		const std::string	secondSourceStr	= generateSecondSource();
    661 
    662 		const char*			firstSource		= firstSourceStr.c_str();
    663 		const char*			secondSource	= secondSourceStr.c_str();
    664 
    665 		log << TestLog::Message << "Setting shader source." << TestLog::EndMessage;
    666 
    667 		shader.setSources(1, &firstSource, 0);
    668 		GLU_CHECK();
    669 
    670 		log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage;
    671 
    672 		shader.setSources(1, &secondSource, 0);
    673 		GLU_CHECK();
    674 
    675 		verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr);
    676 	}
    677 
    678 private:
    679 	glu::ShaderType	m_shaderType;
    680 };
    681 
    682 // glShaderSource() split source case
    683 
    684 class ShaderSourceSplitCase : public ApiCase
    685 {
    686 public:
    687 	ShaderSourceSplitCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType, const int numSlices, const deUint32 flags = 0)
    688 		: ApiCase			(context, name, desc)
    689 		, m_rnd				(deStringHash(getName()) ^ 0x4fb2337d)
    690 		, m_shaderType		(shaderType)
    691 		, m_numSlices		(numSlices)
    692 		, m_explicitLengths	((flags & CASE_EXPLICIT_SOURCE_LENGTHS)	!= 0)
    693 		, m_randomNullTerm	((flags & CASE_RANDOM_NULL_TERMINATED)	!= 0)
    694 	{
    695 		DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
    696 	}
    697 
    698 	virtual ~ShaderSourceSplitCase (void)
    699 	{
    700 	}
    701 
    702 	std::string generateFullSource (void)
    703 	{
    704 		std::ostringstream out;
    705 
    706 		out << "#version 300 es\n";
    707 		out << "precision mediump float;\n";
    708 
    709 		if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
    710 			out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
    711 
    712 		out << "void main()\n";
    713 		out << "{\n";
    714 		out << "	float variable = 1.0f;\n";
    715 
    716 		if		(m_shaderType == glu::SHADERTYPE_VERTEX)	out << "	gl_Position = vec4(variable);\n";
    717 		else if	(m_shaderType == glu::SHADERTYPE_FRAGMENT)	out << "	o_fragColor = vec4(variable);\n";
    718 
    719 		out << "}\n";
    720 
    721 		return out.str();
    722 	}
    723 
    724 	void insertRandomNullTermStrings (ShaderSources& sources)
    725 	{
    726 		const int			numInserts	= de::max(m_numSlices >> 2, 1);
    727 		std::vector<int>	indices		(sources.strings.size(), 0);
    728 
    729 		DE_ASSERT(sources.lengths.size() > 0);
    730 		DE_ASSERT(sources.lengths.size() == sources.strings.size());
    731 
    732 		for (int i = 0; i < (int)sources.strings.size(); i++)
    733 			indices[i] = i;
    734 
    735 		m_rnd.shuffle(indices.begin(), indices.end());
    736 
    737 		for (int i = 0; i < numInserts; i++)
    738 		{
    739 			const int			ndx				= indices[i];
    740 			const int			unpaddedLength	= sources.lengths[ndx];
    741 			const std::string	unpaddedString	= sources.strings[ndx].substr(0, unpaddedLength);
    742 
    743 			sources.strings[ndx] = unpaddedString;
    744 			sources.lengths[ndx] = m_rnd.getInt(-10, -1);
    745 		}
    746 	}
    747 
    748 	void generateSources (ShaderSources& sources)
    749 	{
    750 		const size_t	paddingLength	= (m_explicitLengths ? 10 : 0);
    751 		std::string		str				= generateFullSource();
    752 
    753 		sliceSourceString(str, sources, m_numSlices, paddingLength);
    754 
    755 		if (m_randomNullTerm)
    756 			insertRandomNullTermStrings(sources);
    757 	}
    758 
    759 	void buildProgram (glu::Shader& shader)
    760 	{
    761 		TestLog&				log					= m_testCtx.getLog();
    762 		glu::RenderContext&		renderCtx			= m_context.getRenderContext();
    763 
    764 		const glu::ShaderType	supportShaderType	= (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT);
    765 		const char*				supportShaderSource	= getSimpleShaderSource(supportShaderType);
    766 		glu::Shader				supportShader		(renderCtx, supportShaderType);
    767 
    768 		glu::Program			program				(renderCtx);
    769 
    770 		supportShader.setSources(1, &supportShaderSource, 0);
    771 		supportShader.compile();
    772 
    773 		program.attachShader(shader.getShader());
    774 		program.attachShader(supportShader.getShader());
    775 
    776 		program.link();
    777 
    778 		if (m_shaderType == glu::SHADERTYPE_VERTEX)
    779 			logVertexFragmentProgram(log, renderCtx, program, shader, supportShader);
    780 		else
    781 			logVertexFragmentProgram(log, renderCtx, program, supportShader, shader);
    782 	}
    783 
    784 	void test (void)
    785 	{
    786 		TestLog&			log			= m_testCtx.getLog();
    787 		glu::RenderContext&	renderCtx	= m_context.getRenderContext();
    788 
    789 		ShaderSources		sources;
    790 		glu::Shader			shader		(renderCtx, m_shaderType);
    791 
    792 		generateSources(sources);
    793 		setShaderSources(shader, sources);
    794 		shader.compile();
    795 
    796 		buildProgram(shader);
    797 
    798 		if (!shader.getCompileStatus())
    799 		{
    800 			log << TestLog::Message << "Compilation failed." << TestLog::EndMessage;
    801 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
    802 		}
    803 	}
    804 
    805 private:
    806 	de::Random				m_rnd;
    807 
    808 	const glu::ShaderType	m_shaderType;
    809 	const int				m_numSlices;
    810 
    811 	const bool				m_explicitLengths;
    812 	const bool				m_randomNullTerm;
    813 };
    814 
    815 // Base class for program state persistence cases
    816 
    817 class ProgramStateCase : public ApiCase
    818 {
    819 public:
    820 					ProgramStateCase	(Context& context, const char* name, const char* desc, glu::ShaderType shaderType);
    821 	virtual			~ProgramStateCase	(void)	{}
    822 
    823 	void			buildProgram		(glu::Program& program, ShaderAllocator& shaders);
    824 	void			verify				(glu::Program& program, const glu::ProgramInfo& reference);
    825 
    826 	void			test				(void);
    827 
    828 	virtual void	executeForProgram	(glu::Program& program, ShaderAllocator& shaders)	= 0;
    829 
    830 protected:
    831 	de::Random					m_rnd;
    832 	const glu::ShaderType		m_shaderType;
    833 };
    834 
    835 ProgramStateCase::ProgramStateCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    836 	: ApiCase		(context, name, desc)
    837 	, m_rnd			(deStringHash(name) ^ 0x713de0ca)
    838 	, m_shaderType	(shaderType)
    839 {
    840 	DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
    841 }
    842 
    843 void ProgramStateCase::buildProgram (glu::Program& program, ShaderAllocator& shaders)
    844 {
    845 	TestLog&		log			= m_testCtx.getLog();
    846 
    847 	glu::Shader&	vertShader	= shaders.createShader(glu::SHADERTYPE_VERTEX);
    848 	glu::Shader&	fragShader	= shaders.createShader(glu::SHADERTYPE_FRAGMENT);
    849 
    850 	vertShader.compile();
    851 	fragShader.compile();
    852 
    853 	program.attachShader(vertShader.getShader());
    854 	program.attachShader(fragShader.getShader());
    855 	program.link();
    856 
    857 	logProgram(log, m_context.getRenderContext(), program, shaders);
    858 }
    859 
    860 void ProgramStateCase::verify (glu::Program& program, const glu::ProgramInfo& reference)
    861 {
    862 	TestLog&				log			= m_testCtx.getLog();
    863 	const glu::ProgramInfo&	programInfo	= program.getInfo();
    864 
    865 	if (!programInfo.linkOk)
    866 	{
    867 		log << TestLog::Message << "Fail, link status may only change as a result of linking or loading a program binary." << TestLog::EndMessage;
    868 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed");
    869 	}
    870 
    871 	if (programInfo.linkTimeUs != reference.linkTimeUs)
    872 	{
    873 		log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage;
    874 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed");
    875 	}
    876 
    877 	if (programInfo.infoLog != reference.infoLog)
    878 	{
    879 		log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage;
    880 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed");
    881 	}
    882 }
    883 
    884 void ProgramStateCase::test (void)
    885 {
    886 	TestLog&				log			= m_testCtx.getLog();
    887 	glu::RenderContext&		renderCtx	= m_context.getRenderContext();
    888 
    889 	ConstantShaderGenerator	sourceGen	(m_rnd);
    890 
    891 	ShaderAllocator			shaders		(renderCtx, sourceGen);
    892 	glu::Program			program		(renderCtx);
    893 
    894 	buildProgram(program, shaders);
    895 
    896 	if (program.getLinkStatus())
    897 	{
    898 		glu::ProgramInfo programInfo = program.getInfo();
    899 
    900 		executeForProgram(program, shaders);
    901 
    902 		verify(program, programInfo);
    903 
    904 		logProgram(log, renderCtx, program, shaders);
    905 	}
    906 	else
    907 	{
    908 		log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
    909 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
    910 	}
    911 }
    912 
    913 // Program state case utilities
    914 
    915 namespace
    916 {
    917 
    918 template<class T>
    919 void addProgramStateCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc)
    920 {
    921 	for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
    922 	{
    923 		const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
    924 		const std::string		shaderTypeName	= getShaderTypeName(shaderType);
    925 
    926 		const std::string		caseName		= name + "_" + shaderTypeName;
    927 		const std::string		caseDesc		= "Build program, " + desc + ", for " + shaderTypeName + " shader.";
    928 
    929 		group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
    930 	}
    931 }
    932 
    933 } // anonymous
    934 
    935 // Specialized program state cases
    936 
    937 class ProgramStateDetachShaderCase : public ProgramStateCase
    938 {
    939 public:
    940 	ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    941 		: ProgramStateCase (context, name, desc, shaderType)
    942 	{
    943 	}
    944 
    945 	virtual ~ProgramStateDetachShaderCase (void)
    946 	{
    947 	}
    948 
    949 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    950 	{
    951 		TestLog&		log			= m_testCtx.getLog();
    952 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    953 
    954 		log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    955 		program.detachShader(caseShader.getShader());
    956 	}
    957 };
    958 
    959 class ProgramStateReattachShaderCase : public ProgramStateCase
    960 {
    961 public:
    962 	ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    963 		: ProgramStateCase (context, name, desc, shaderType)
    964 	{
    965 	}
    966 
    967 	virtual ~ProgramStateReattachShaderCase (void)
    968 	{
    969 	}
    970 
    971 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    972 	{
    973 		TestLog&		log			= m_testCtx.getLog();
    974 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    975 
    976 		log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
    977 		program.detachShader(caseShader.getShader());
    978 		program.attachShader(caseShader.getShader());
    979 	}
    980 };
    981 
    982 class ProgramStateDeleteShaderCase : public ProgramStateCase
    983 {
    984 public:
    985 	ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
    986 		: ProgramStateCase (context, name, desc, shaderType)
    987 	{
    988 	}
    989 
    990 	virtual ~ProgramStateDeleteShaderCase (void)
    991 	{
    992 	}
    993 
    994 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
    995 	{
    996 		TestLog&		log			= m_testCtx.getLog();
    997 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
    998 
    999 		log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1000 		program.detachShader(caseShader.getShader());
   1001 		shaders.deleteShader(m_shaderType);
   1002 	}
   1003 };
   1004 
   1005 class ProgramStateReplaceShaderCase : public ProgramStateCase
   1006 {
   1007 public:
   1008 	ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1009 		: ProgramStateCase (context, name, desc, shaderType)
   1010 	{
   1011 	}
   1012 
   1013 	virtual ~ProgramStateReplaceShaderCase (void)
   1014 	{
   1015 	}
   1016 
   1017 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1018 	{
   1019 		TestLog&		log			= m_testCtx.getLog();
   1020 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1021 
   1022 		log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1023 		program.detachShader(caseShader.getShader());
   1024 		shaders.deleteShader(m_shaderType);
   1025 		program.attachShader(shaders.createShader(m_shaderType).getShader());
   1026 	}
   1027 };
   1028 
   1029 class ProgramStateRecompileShaderCase : public ProgramStateCase
   1030 {
   1031 public:
   1032 	ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1033 		: ProgramStateCase (context, name, desc, shaderType)
   1034 	{
   1035 	}
   1036 
   1037 	virtual ~ProgramStateRecompileShaderCase (void)
   1038 	{
   1039 	}
   1040 
   1041 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1042 	{
   1043 		TestLog&		log			= m_testCtx.getLog();
   1044 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1045 
   1046 		log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1047 		caseShader.compile();
   1048 		DE_UNREF(program);
   1049 	}
   1050 };
   1051 
   1052 class ProgramStateReplaceSourceCase : public ProgramStateCase
   1053 {
   1054 public:
   1055 	ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1056 		: ProgramStateCase (context, name, desc, shaderType)
   1057 	{
   1058 	}
   1059 
   1060 	virtual ~ProgramStateReplaceSourceCase (void)
   1061 	{
   1062 	}
   1063 
   1064 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1065 	{
   1066 		TestLog&		log			= m_testCtx.getLog();
   1067 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1068 
   1069 		log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage;
   1070 		shaders.setSource(m_shaderType);
   1071 		caseShader.compile();
   1072 		DE_UNREF(program);
   1073 	}
   1074 };
   1075 
   1076 // Program binary utilities
   1077 
   1078 namespace
   1079 {
   1080 
   1081 struct ProgramBinary
   1082 {
   1083 	GLenum					format;
   1084 	std::vector<deUint8>	data;
   1085 };
   1086 
   1087 bool programBinariesEqual (const ProgramBinary& first, const ProgramBinary& second)
   1088 {
   1089 	if ((first.format != second.format) || (first.data.size() != second.data.size()))
   1090 		return false;
   1091 
   1092 	return std::equal(first.data.begin(), first.data.end(), second.data.begin());
   1093 }
   1094 
   1095 } // anonymous
   1096 
   1097 // Base class for program binary cases
   1098 
   1099 class ProgramBinaryCase : public TestCase, protected glu::CallLogWrapper
   1100 {
   1101 public:
   1102 							ProgramBinaryCase	(Context& context, const char* name, const char* desc);
   1103 	virtual					~ProgramBinaryCase	(void);
   1104 
   1105 	void					getBinaryFormats	(std::vector<GLenum>& out);
   1106 	bool					isFormatSupported	(const glw::GLenum format) const;
   1107 
   1108 	void					getProgramBinary	(ProgramBinary& out, GLuint program);
   1109 	void					loadProgramBinary	(ProgramBinary& binary, GLuint program);
   1110 
   1111 	void					verifyProgramBinary	(ProgramBinary& binary);
   1112 
   1113 	void					init				(void);
   1114 	IterateResult			iterate				(void);
   1115 
   1116 	virtual void			test				(void) = 0;
   1117 
   1118 protected:
   1119 	std::vector<GLenum>		m_formats;
   1120 };
   1121 
   1122 ProgramBinaryCase::ProgramBinaryCase (Context& context, const char* name, const char* desc)
   1123 		: TestCase			(context, name, desc)
   1124 		, CallLogWrapper	(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
   1125 {
   1126 }
   1127 
   1128 ProgramBinaryCase::~ProgramBinaryCase (void)
   1129 {
   1130 }
   1131 
   1132 void ProgramBinaryCase::getBinaryFormats (std::vector<GLenum>& out)
   1133 {
   1134 	GLint numFormats = -1;
   1135 	glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats);
   1136 
   1137 	out.clear();
   1138 
   1139 	if (numFormats > 0)
   1140 	{
   1141 		out.resize(numFormats, 0);
   1142 
   1143 		glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, (GLint*)&out[0]);
   1144 	}
   1145 }
   1146 
   1147 bool ProgramBinaryCase::isFormatSupported (const glw::GLenum format) const
   1148 {
   1149 	return (std::find(m_formats.begin(), m_formats.end(), format) != m_formats.end());
   1150 }
   1151 
   1152 void ProgramBinaryCase::getProgramBinary (ProgramBinary& out, GLuint program)
   1153 {
   1154 	GLint binaryLength = -1;
   1155 	glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
   1156 
   1157 	if (binaryLength > 0)
   1158 	{
   1159 		GLsizei	actualLength;
   1160 		GLenum	format;
   1161 
   1162 		out.data.clear();
   1163 		out.data.resize(binaryLength, 0);
   1164 
   1165 		GLU_CHECK_CALL(glGetProgramBinary(program, (GLsizei)out.data.size(), &actualLength, &format, &(out.data[0])));
   1166 
   1167 		TCU_CHECK(actualLength == binaryLength);
   1168 
   1169 		out.format = format;
   1170 	}
   1171 }
   1172 
   1173 void ProgramBinaryCase::loadProgramBinary (ProgramBinary& binary, GLuint program)
   1174 {
   1175 	glProgramBinary(program, binary.format, &binary.data[0], (GLsizei)binary.data.size());
   1176 	GLU_CHECK_MSG("Failed to load program binary.");
   1177 }
   1178 
   1179 void ProgramBinaryCase::verifyProgramBinary (ProgramBinary& binary)
   1180 {
   1181 	TestLog& log = m_testCtx.getLog();
   1182 
   1183 	if (!isFormatSupported(binary.format))
   1184 	{
   1185 		log << TestLog::Message << "Program binary format " << binary.format << " is not among the supported formats reported by the platform." << TestLog::EndMessage;
   1186 
   1187 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid format");
   1188 	}
   1189 }
   1190 
   1191 void ProgramBinaryCase::init (void)
   1192 {
   1193 	getBinaryFormats(m_formats);
   1194 }
   1195 
   1196 tcu::TestNode::IterateResult ProgramBinaryCase::iterate (void)
   1197 {
   1198 	TestLog&	log	= m_testCtx.getLog();
   1199 
   1200 	if (m_formats.empty())
   1201 	{
   1202 		log << TestLog::Message << "No program binary formats are supported." << TestLog::EndMessage;
   1203 
   1204 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
   1205 	}
   1206 	else
   1207 	{
   1208 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1209 
   1210 		enableLogging(true);
   1211 		test();
   1212 	}
   1213 
   1214 	return STOP;
   1215 }
   1216 
   1217 // Simple program binary case
   1218 
   1219 class ProgramBinarySimpleCase : public ProgramBinaryCase
   1220 {
   1221 public:
   1222 	ProgramBinarySimpleCase (Context& context, const char* name, const char* desc)
   1223 		: ProgramBinaryCase(context, name, desc)
   1224 	{
   1225 	}
   1226 
   1227 	virtual ~ProgramBinarySimpleCase (void)
   1228 	{
   1229 	}
   1230 
   1231 	void test (void)
   1232 	{
   1233 		const std::string			vertSrc	= getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
   1234 		const std::string			fragSrc	= getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
   1235 
   1236 		const glu::ProgramSources	sources	= glu::makeVtxFragSources(vertSrc, fragSrc);
   1237 
   1238 		glu::ShaderProgram			program	(m_context.getRenderContext(), sources);
   1239 
   1240 		if (program.isOk())
   1241 		{
   1242 			ProgramBinary binary;
   1243 
   1244 			getProgramBinary(binary, program.getProgram());
   1245 			verifyProgramBinary(binary);
   1246 		}
   1247 	}
   1248 };
   1249 
   1250 // Program binary uniform reset case
   1251 
   1252 class ProgramBinaryUniformResetCase : public ProgramBinaryCase
   1253 {
   1254 public:
   1255 	ProgramBinaryUniformResetCase (Context& context, const char* name, const char* desc)
   1256 		: ProgramBinaryCase	(context, name, desc)
   1257 		, m_rnd				(deStringHash(name) ^ 0xf2b48c6a)
   1258 	{
   1259 	}
   1260 
   1261 	virtual ~ProgramBinaryUniformResetCase (void)
   1262 	{
   1263 	}
   1264 
   1265 	std::string getShaderSource (const glu::ShaderType shaderType) const
   1266 	{
   1267 		const char* vertSrc =
   1268 			"#version 300 es\n"
   1269 			"uniform bool u_boolVar;\n"
   1270 			"uniform highp int u_intVar;\n"
   1271 			"uniform highp float u_floatVar;\n\n"
   1272 			"in highp vec4 a_position;\n\n"
   1273 			"void main (void)\n"
   1274 			"{\n"
   1275 			"	gl_Position = a_position;\n"
   1276 			"}\n";
   1277 		const char* fragSrc =
   1278 			"#version 300 es\n"
   1279 			"uniform bool u_boolVar;\n"
   1280 			"uniform highp int u_intVar;\n"
   1281 			"uniform highp float u_floatVar;\n\n"
   1282 			"layout(location = 0) out mediump vec4 o_fragColor;\n\n"
   1283 			"void main (void)\n"
   1284 			"{\n"
   1285 			"	mediump float refAll = float(u_boolVar) + float(u_intVar) + u_floatVar;\n"
   1286 			"	o_fragColor = vec4(refAll);\n"
   1287 			"}\n";
   1288 
   1289 		DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
   1290 
   1291 		return (shaderType == glu::SHADERTYPE_VERTEX) ? vertSrc : fragSrc;
   1292 	}
   1293 
   1294 	void setUniformsRandom (glu::ShaderProgram& program)
   1295 	{
   1296 		TestLog&		log		= m_testCtx.getLog();
   1297 		const deUint32	glProg	= program.getProgram();
   1298 
   1299 		log << TestLog::Message << "Setting uniforms to random non-zero values." << TestLog::EndMessage;
   1300 
   1301 		glUseProgram(glProg);
   1302 
   1303 		{
   1304 			const GLint		boolLoc		= glGetUniformLocation(glProg, "u_boolVar");
   1305 			const GLint		intLoc		= glGetUniformLocation(glProg, "u_intVar");
   1306 			const GLint		floatLoc	= glGetUniformLocation(glProg, "u_floatVar");
   1307 
   1308 			const deInt32	intVal		= m_rnd.getInt(1, 1000);
   1309 			const float		floatVal	= m_rnd.getFloat(1.0, 1000.0);
   1310 
   1311 			glUniform1i(boolLoc,	GL_TRUE);
   1312 			glUniform1f(floatLoc,	floatVal);
   1313 			glUniform1i(intLoc,		intVal);
   1314 		}
   1315 	}
   1316 
   1317 	void verifyUniformInt (glu::ShaderProgram& program, const std::string& name)
   1318 	{
   1319 		const GLint		intLoc	= glGetUniformLocation(program.getProgram(), name.c_str());
   1320 		GLint			intVar	= -1;
   1321 
   1322 		glGetUniformiv(program.getProgram(), intLoc, &intVar);
   1323 
   1324 		if (intVar != 0)
   1325 		{
   1326 			m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name << ", received: " << intVar << TestLog::EndMessage;
   1327 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset");
   1328 		}
   1329 	}
   1330 
   1331 	void verifyUniformFloat (glu::ShaderProgram& program, const std::string& name)
   1332 	{
   1333 		const GLint	floatLoc	= glGetUniformLocation(program.getProgram(), name.c_str());
   1334 		GLfloat		floatVar	= -1;
   1335 
   1336 		glGetUniformfv(program.getProgram(), floatLoc, &floatVar);
   1337 
   1338 		if (floatVar != 0.0f)
   1339 		{
   1340 			m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name << ", received: " << de::toString(floatVar) << TestLog::EndMessage;
   1341 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset");
   1342 		}
   1343 	}
   1344 
   1345 	void verifyUniformsReset (glu::ShaderProgram& program)
   1346 	{
   1347 		m_testCtx.getLog() << TestLog::Message << "Verifying uniform reset to 0/false." << TestLog::EndMessage;
   1348 
   1349 		verifyUniformInt	(program,	"u_boolVar");
   1350 		verifyUniformInt	(program,	"u_intVar");
   1351 		verifyUniformFloat	(program,	"u_floatVar");
   1352 	}
   1353 
   1354 	void test (void)
   1355 	{
   1356 		TestLog&					log		= m_testCtx.getLog();
   1357 
   1358 		const std::string			vertSrc	= getShaderSource(glu::SHADERTYPE_VERTEX);
   1359 		const std::string			fragSrc	= getShaderSource(glu::SHADERTYPE_FRAGMENT);
   1360 
   1361 		const glu::ProgramSources	sources	= glu::makeVtxFragSources(vertSrc, fragSrc);
   1362 
   1363 		glu::ShaderProgram			program	(m_context.getRenderContext(), sources);
   1364 
   1365 		log << program;
   1366 
   1367 		TCU_CHECK_MSG(program.isOk(), "Couldn't build program");
   1368 
   1369 		{
   1370 			ProgramBinary binary;
   1371 
   1372 			getProgramBinary(binary, program.getProgram());
   1373 			verifyProgramBinary(binary);
   1374 
   1375 			setUniformsRandom(program);
   1376 
   1377 			log << TestLog::Message << "Rendering test image and reloading binary" << TestLog::EndMessage;
   1378 
   1379 			drawWithProgram(m_context.getRenderContext(), program.getProgram());
   1380 			loadProgramBinary(binary, program.getProgram());
   1381 
   1382 			verifyUniformsReset(program);
   1383 		}
   1384 	}
   1385 private:
   1386 	de::Random	m_rnd;
   1387 };
   1388 
   1389 // Base class for program state persistence cases
   1390 
   1391 class ProgramBinaryPersistenceCase : public ProgramBinaryCase
   1392 {
   1393 public:
   1394 					ProgramBinaryPersistenceCase	(Context& context, const char* name, const char* desc, glu::ShaderType shaderType);
   1395 	virtual			~ProgramBinaryPersistenceCase	(void) {}
   1396 
   1397 	void			buildProgram					(glu::Program& program, ShaderAllocator& shaders);
   1398 
   1399 	void			test							(void);
   1400 
   1401 	virtual void	executeForProgram				(glu::Program& program, ShaderAllocator& shaders)	= 0;
   1402 	virtual void	verify							(glu::Program& program, const ProgramBinary& binary);
   1403 
   1404 protected:
   1405 	de::Random				m_rnd;
   1406 	const glu::ShaderType	m_shaderType;
   1407 };
   1408 
   1409 ProgramBinaryPersistenceCase::ProgramBinaryPersistenceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1410 	: ProgramBinaryCase	(context, name, desc)
   1411 	, m_rnd				(deStringHash(name) ^ 0x713de0ca)
   1412 	, m_shaderType		(shaderType)
   1413 {
   1414 	DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
   1415 }
   1416 
   1417 void ProgramBinaryPersistenceCase::buildProgram (glu::Program& program, ShaderAllocator& shaders)
   1418 {
   1419 	TestLog&		log			= m_testCtx.getLog();
   1420 
   1421 	glu::Shader&	vertShader	= shaders.createShader(glu::SHADERTYPE_VERTEX);
   1422 	glu::Shader&	fragShader	= shaders.createShader(glu::SHADERTYPE_FRAGMENT);
   1423 
   1424 	vertShader.compile();
   1425 	fragShader.compile();
   1426 
   1427 	program.attachShader(vertShader.getShader());
   1428 	program.attachShader(fragShader.getShader());
   1429 	program.link();
   1430 
   1431 	logProgram(log, m_context.getRenderContext(), program, shaders);
   1432 }
   1433 
   1434 void ProgramBinaryPersistenceCase::verify (glu::Program& program, const ProgramBinary& binary)
   1435 {
   1436 	TestLog&		log				= m_testCtx.getLog();
   1437 	ProgramBinary	currentBinary;
   1438 
   1439 	getProgramBinary(currentBinary, program.getProgram());
   1440 
   1441 	if (!programBinariesEqual(binary, currentBinary))
   1442 	{
   1443 		log << TestLog::Message << "Fail, program binary may only change as a result of linking or loading." << TestLog::EndMessage;
   1444 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program binary changed");
   1445 	}
   1446 }
   1447 
   1448 void ProgramBinaryPersistenceCase::test (void)
   1449 {
   1450 	TestLog&				log			= m_testCtx.getLog();
   1451 	glu::RenderContext&		renderCtx	= m_context.getRenderContext();
   1452 
   1453 	ConstantShaderGenerator	sourceGen	(m_rnd);
   1454 
   1455 	ShaderAllocator			shaders		(renderCtx, sourceGen);
   1456 	glu::Program			program		(renderCtx);
   1457 
   1458 	buildProgram(program, shaders);
   1459 
   1460 	if (program.getLinkStatus())
   1461 	{
   1462 		ProgramBinary binary;
   1463 		getProgramBinary(binary, program.getProgram());
   1464 
   1465 		executeForProgram(program, shaders);
   1466 
   1467 		verify(program, binary);
   1468 
   1469 		logProgram(log, renderCtx, program, shaders);
   1470 	}
   1471 	else
   1472 	{
   1473 		log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
   1474 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
   1475 	}
   1476 }
   1477 
   1478 // Program state case utilities
   1479 
   1480 namespace
   1481 {
   1482 
   1483 template<class T>
   1484 void addProgramBinaryPersistenceCase (TestCaseGroup* group, Context& context, const std::string& name, const std::string& desc)
   1485 {
   1486 	for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
   1487 	{
   1488 		const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
   1489 		const std::string		shaderTypeName	= getShaderTypeName(shaderType);
   1490 
   1491 		const std::string		caseName		= name + "_" + shaderTypeName;
   1492 		const std::string		caseDesc		= "Build program, " + desc + ", for " + shaderTypeName + " shader.";
   1493 
   1494 		group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
   1495 	}
   1496 }
   1497 
   1498 } // anonymous
   1499 
   1500 // Specialized program state cases
   1501 
   1502 class ProgramBinaryPersistenceDetachShaderCase : public ProgramBinaryPersistenceCase
   1503 {
   1504 public:
   1505 	ProgramBinaryPersistenceDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1506 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1507 	{
   1508 	}
   1509 
   1510 	virtual ~ProgramBinaryPersistenceDetachShaderCase (void)
   1511 	{
   1512 	}
   1513 
   1514 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1515 	{
   1516 		TestLog&		log			= m_testCtx.getLog();
   1517 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1518 
   1519 		log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1520 		program.detachShader(caseShader.getShader());
   1521 	}
   1522 };
   1523 
   1524 class ProgramBinaryPersistenceReattachShaderCase : public ProgramBinaryPersistenceCase
   1525 {
   1526 public:
   1527 	ProgramBinaryPersistenceReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1528 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1529 	{
   1530 	}
   1531 
   1532 	virtual ~ProgramBinaryPersistenceReattachShaderCase (void)
   1533 	{
   1534 	}
   1535 
   1536 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1537 	{
   1538 		TestLog&		log			= m_testCtx.getLog();
   1539 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1540 
   1541 		log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1542 		program.detachShader(caseShader.getShader());
   1543 		program.attachShader(caseShader.getShader());
   1544 	}
   1545 };
   1546 
   1547 class ProgramBinaryPersistenceDeleteShaderCase : public ProgramBinaryPersistenceCase
   1548 {
   1549 public:
   1550 	ProgramBinaryPersistenceDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1551 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1552 	{
   1553 	}
   1554 
   1555 	virtual ~ProgramBinaryPersistenceDeleteShaderCase (void)
   1556 	{
   1557 	}
   1558 
   1559 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1560 	{
   1561 		TestLog&		log			= m_testCtx.getLog();
   1562 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1563 
   1564 		log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1565 		program.detachShader(caseShader.getShader());
   1566 		shaders.deleteShader(m_shaderType);
   1567 	}
   1568 };
   1569 
   1570 class ProgramBinaryPersistenceReplaceShaderCase : public ProgramBinaryPersistenceCase
   1571 {
   1572 public:
   1573 	ProgramBinaryPersistenceReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1574 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1575 	{
   1576 	}
   1577 
   1578 	virtual ~ProgramBinaryPersistenceReplaceShaderCase (void)
   1579 	{
   1580 	}
   1581 
   1582 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1583 	{
   1584 		TestLog&		log			= m_testCtx.getLog();
   1585 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1586 
   1587 		log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1588 		program.detachShader(caseShader.getShader());
   1589 		shaders.deleteShader(m_shaderType);
   1590 		program.attachShader(shaders.createShader(m_shaderType).getShader());
   1591 	}
   1592 };
   1593 
   1594 class ProgramBinaryPersistenceRecompileShaderCase : public ProgramBinaryPersistenceCase
   1595 {
   1596 public:
   1597 	ProgramBinaryPersistenceRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1598 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1599 	{
   1600 	}
   1601 
   1602 	virtual ~ProgramBinaryPersistenceRecompileShaderCase (void)
   1603 	{
   1604 	}
   1605 
   1606 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1607 	{
   1608 		TestLog&		log			= m_testCtx.getLog();
   1609 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1610 
   1611 		log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader" << TestLog::EndMessage;
   1612 		caseShader.compile();
   1613 		DE_UNREF(program);
   1614 	}
   1615 };
   1616 
   1617 class ProgramBinaryPersistenceReplaceSourceCase : public ProgramBinaryPersistenceCase
   1618 {
   1619 public:
   1620 	ProgramBinaryPersistenceReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
   1621 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
   1622 	{
   1623 	}
   1624 
   1625 	virtual ~ProgramBinaryPersistenceReplaceSourceCase (void)
   1626 	{
   1627 	}
   1628 
   1629 	void executeForProgram (glu::Program& program, ShaderAllocator& shaders)
   1630 	{
   1631 		TestLog&		log			= m_testCtx.getLog();
   1632 		glu::Shader&	caseShader	= shaders.get(m_shaderType);
   1633 
   1634 		log << TestLog::Message << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling" << TestLog::EndMessage;
   1635 		shaders.setSource(m_shaderType);
   1636 		caseShader.compile();
   1637 		DE_UNREF(program);
   1638 	}
   1639 };
   1640 
   1641 // Test group
   1642 
   1643 ShaderApiTests::ShaderApiTests (Context& context)
   1644 	: TestCaseGroup(context, "shader_api", "Shader API Cases")
   1645 {
   1646 }
   1647 
   1648 ShaderApiTests::~ShaderApiTests (void)
   1649 {
   1650 }
   1651 
   1652 void ShaderApiTests::init (void)
   1653 {
   1654 	// create and delete shaders
   1655 	{
   1656 		TestCaseGroup* createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests");
   1657 		addChild(createDeleteGroup);
   1658 
   1659 		createDeleteGroup->addChild(new CreateShaderCase(m_context,	"create_vertex_shader",		"Create vertex shader object",		glu::SHADERTYPE_VERTEX));
   1660 		createDeleteGroup->addChild(new CreateShaderCase(m_context,	"create_fragment_shader",	"Create fragment shader object",	glu::SHADERTYPE_FRAGMENT));
   1661 
   1662 		createDeleteGroup->addChild(new DeleteShaderCase(m_context,	"delete_vertex_fragment",	"Delete vertex shader and fragment shader"));
   1663 	}
   1664 
   1665 	// compile and link
   1666 	{
   1667 		TestCaseGroup* compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests");
   1668 		addChild(compileLinkGroup);
   1669 
   1670 		compileLinkGroup->addChild(new CompileShaderCase(m_context,	"compile_vertex_shader",	"Compile vertex shader",	glu::SHADERTYPE_VERTEX));
   1671 		compileLinkGroup->addChild(new CompileShaderCase(m_context,	"compile_fragment_shader",	"Compile fragment shader",	glu::SHADERTYPE_FRAGMENT));
   1672 
   1673 		compileLinkGroup->addChild(new LinkVertexFragmentCase(m_context,	"link_vertex_fragment",	"Link vertex and fragment shaders"));
   1674 	}
   1675 
   1676 	// shader source
   1677 	{
   1678 		TestCaseGroup* shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests");
   1679 		addChild(shaderSourceGroup);
   1680 
   1681 		for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
   1682 		{
   1683 			const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
   1684 			const std::string		shaderTypeName	= getShaderTypeName(shaderType);
   1685 
   1686 			const std::string		caseName		= std::string("replace_source_") + shaderTypeName;
   1687 			const std::string		caseDesc		= std::string("Replace source code of ") + shaderTypeName + " shader.";
   1688 
   1689 			shaderSourceGroup->addChild(new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType));
   1690 		}
   1691 
   1692 		for (int stringLengthsInt	= 0; stringLengthsInt < 3; stringLengthsInt++)
   1693 		for (int caseNdx = 1; caseNdx <= 3; caseNdx++)
   1694 		for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
   1695 		{
   1696 			const int				numSlices		= 1 << caseNdx;
   1697 			const glu::ShaderType	shaderType		= (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
   1698 
   1699 			const bool				explicitLengths	= (stringLengthsInt != 0);
   1700 			const bool				randomNullTerm	= (stringLengthsInt == 2);
   1701 
   1702 			const deUint32			flags			= (explicitLengths	? CASE_EXPLICIT_SOURCE_LENGTHS	: 0)
   1703 													| (randomNullTerm	? CASE_RANDOM_NULL_TERMINATED	: 0);
   1704 
   1705 			const std::string		caseName		= "split_source_"
   1706 													+ de::toString(numSlices)
   1707 													+ (randomNullTerm ? "_random_negative_length" : (explicitLengths ? "_specify_lengths" : "_null_terminated"))
   1708 													+ ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
   1709 
   1710 			const std::string		caseDesc		= std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex")
   1711 													+ " shader source split into "
   1712 													+ de::toString(numSlices)
   1713 													+ " pieces"
   1714 													+ (explicitLengths ? ", using explicitly specified string lengths" : "")
   1715 													+ (randomNullTerm ? " with random negative length values" : "");
   1716 
   1717 			shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType, numSlices, flags));
   1718 		}
   1719 	}
   1720 
   1721 	// link status and infolog
   1722 	{
   1723 		TestCaseGroup* linkStatusGroup = new TestCaseGroup(m_context, "program_state", "Program state persistence tests");
   1724 		addChild(linkStatusGroup);
   1725 
   1726 		addProgramStateCase<ProgramStateDetachShaderCase>		(linkStatusGroup,	m_context,	"detach_shader",	"detach shader");
   1727 		addProgramStateCase<ProgramStateReattachShaderCase>		(linkStatusGroup,	m_context,	"reattach_shader",	"reattach shader");
   1728 		addProgramStateCase<ProgramStateDeleteShaderCase>		(linkStatusGroup,	m_context,	"delete_shader",	"delete shader");
   1729 		addProgramStateCase<ProgramStateReplaceShaderCase>		(linkStatusGroup,	m_context,	"replace_shader",	"replace shader object");
   1730 		addProgramStateCase<ProgramStateRecompileShaderCase>	(linkStatusGroup,	m_context,	"recompile_shader",	"recompile shader");
   1731 		addProgramStateCase<ProgramStateReplaceSourceCase>		(linkStatusGroup,	m_context,	"replace_source",	"replace shader source");
   1732 	}
   1733 
   1734 	// program binary
   1735 	{
   1736 		TestCaseGroup* programBinaryGroup = new TestCaseGroup(m_context, "program_binary", "Program binary API tests");
   1737 		addChild(programBinaryGroup);
   1738 
   1739 		{
   1740 			TestCaseGroup* simpleCaseGroup = new TestCaseGroup(m_context, "simple", "Simple API tests");
   1741 			programBinaryGroup->addChild(simpleCaseGroup);
   1742 
   1743 			simpleCaseGroup->addChild(new ProgramBinarySimpleCase		(m_context,	"get_program_binary_vertex_fragment",	"Get vertex and fragment shader program binary"));
   1744 			simpleCaseGroup->addChild(new ProgramBinaryUniformResetCase	(m_context,	"uniform_reset_on_binary_load",			"Verify uniform reset on successful load of program binary"));
   1745 		}
   1746 
   1747 		{
   1748 			TestCaseGroup* binaryPersistenceGroup = new TestCaseGroup(m_context, "binary_persistence", "Program binary persistence tests");
   1749 			programBinaryGroup->addChild(binaryPersistenceGroup);
   1750 
   1751 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDetachShaderCase>		(binaryPersistenceGroup,	m_context,	"detach_shader",	"detach shader");
   1752 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReattachShaderCase>		(binaryPersistenceGroup,	m_context,	"reattach_shader",	"reattach shader");
   1753 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDeleteShaderCase>		(binaryPersistenceGroup,	m_context,	"delete_shader",	"delete shader");
   1754 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceShaderCase>		(binaryPersistenceGroup,	m_context,	"replace_shader",	"replace shader object");
   1755 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceRecompileShaderCase>	(binaryPersistenceGroup,	m_context,	"recompile_shader",	"recompile shader");
   1756 			addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceSourceCase>		(binaryPersistenceGroup,	m_context,	"replace_source",	"replace shader source");
   1757 		}
   1758 	}
   1759 }
   1760 
   1761 } // Functional
   1762 } // gles3
   1763 } // deqp
   1764