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 
getSimpleShaderSource(const glu::ShaderType shaderType)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 
setShaderSources(glu::Shader & shader,const ShaderSources & sources)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 
sliceSourceString(const std::string & in,ShaderSources & out,const int numSlices,const size_t paddingLength=0)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 
queryShaderInfo(glu::RenderContext & renderCtx,deUint32 shader,glu::ShaderInfo & info)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 
drawWithProgram(glu::RenderContext & renderCtx,deUint32 program)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:
~SourceGenerator(void)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:
ConstantShaderGenerator(de::Random & rnd)228 				ConstantShaderGenerator		(de::Random& rnd)	: m_rnd(rnd)	{}
~ConstantShaderGenerator(void)229 				~ConstantShaderGenerator	(void)								{}
230 
finished(const glu::ShaderType shaderType) const231 	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 
next(const glu::ShaderType shaderType)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 
get(const glu::ShaderType shaderType)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 
ShaderAllocator(glu::RenderContext & context,SourceGenerator & generator)285 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator)
286 	: m_context	(context)
287 	, m_srcGen	(generator)
288 {
289 }
290 
~ShaderAllocator(void)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 
hasShader(const glu::ShaderType shaderType)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 
createShader(const glu::ShaderType shaderType)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 
deleteShader(const glu::ShaderType shaderType)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 
setSource(const glu::ShaderType shaderType)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 
logShader(TestLog & log,glu::RenderContext & renderCtx,glu::Shader & shader)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 
logProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,ShaderAllocator & shaders)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 
logVertexFragmentProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,glu::Shader & vertShader,glu::Shader & fragShader)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:
CreateShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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 
test(void)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:
CompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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 
checkCompileStatus(const GLuint shaderObject)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 
test(void)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:
SimpleProgramCase(Context & context,const char * name,const char * desc)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 
~SimpleProgramCase(void)453 	virtual ~SimpleProgramCase (void)
454 	{
455 	}
456 
compileShaders(void)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 
linkProgram(void)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 
cleanup(void)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:
DeleteShaderCase(Context & context,const char * name,const char * desc)513 	DeleteShaderCase (Context& context, const char* name, const char* desc)
514 		: SimpleProgramCase (context, name, desc)
515 	{
516 	}
517 
checkDeleteStatus(GLuint shader)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 
deleteShaders(void)527 	void deleteShaders (void)
528 	{
529 		glDeleteShader(m_vertShader);
530 		glDeleteShader(m_fragShader);
531 		GLU_CHECK();
532 	}
533 
test(void)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:
LinkVertexFragmentCase(Context & context,const char * name,const char * desc)555 	LinkVertexFragmentCase (Context& context, const char* name, const char* desc)
556 		: SimpleProgramCase (context, name, desc)
557 	{
558 	}
559 
checkLinkStatus(const GLuint programObject)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 
test(void)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:
ShaderSourceReplaceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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 
generateFirstSource(void)590 	std::string generateFirstSource (void)
591 	{
592 		return getSimpleShaderSource(m_shaderType);
593 	}
594 
generateSecondSource(void)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 
getSourceLength(glu::Shader & shader)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 
readSource(glu::Shader & shader)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 
verifyShaderSourceReplaced(glu::Shader & shader,const std::string & firstSource,const std::string & secondSource)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 
test(void)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:
ShaderSourceSplitCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType,const int numSlices,const deUint32 flags=0)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 
~ShaderSourceSplitCase(void)698 	virtual ~ShaderSourceSplitCase (void)
699 	{
700 	}
701 
generateFullSource(void)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 
insertRandomNullTermStrings(ShaderSources & sources)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 
generateSources(ShaderSources & sources)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 
buildProgram(glu::Shader & shader)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 
test(void)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);
~ProgramStateCase(void)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 
ProgramStateCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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 
buildProgram(glu::Program & program,ShaderAllocator & shaders)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 
verify(glu::Program & program,const glu::ProgramInfo & reference)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 
test(void)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>
addProgramStateCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)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:
ProgramStateDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)940 	ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
941 		: ProgramStateCase (context, name, desc, shaderType)
942 	{
943 	}
944 
~ProgramStateDetachShaderCase(void)945 	virtual ~ProgramStateDetachShaderCase (void)
946 	{
947 	}
948 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)962 	ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
963 		: ProgramStateCase (context, name, desc, shaderType)
964 	{
965 	}
966 
~ProgramStateReattachShaderCase(void)967 	virtual ~ProgramStateReattachShaderCase (void)
968 	{
969 	}
970 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)985 	ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
986 		: ProgramStateCase (context, name, desc, shaderType)
987 	{
988 	}
989 
~ProgramStateDeleteShaderCase(void)990 	virtual ~ProgramStateDeleteShaderCase (void)
991 	{
992 	}
993 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1008 	ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1009 		: ProgramStateCase (context, name, desc, shaderType)
1010 	{
1011 	}
1012 
~ProgramStateReplaceShaderCase(void)1013 	virtual ~ProgramStateReplaceShaderCase (void)
1014 	{
1015 	}
1016 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1032 	ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1033 		: ProgramStateCase (context, name, desc, shaderType)
1034 	{
1035 	}
1036 
~ProgramStateRecompileShaderCase(void)1037 	virtual ~ProgramStateRecompileShaderCase (void)
1038 	{
1039 	}
1040 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1055 	ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1056 		: ProgramStateCase (context, name, desc, shaderType)
1057 	{
1058 	}
1059 
~ProgramStateReplaceSourceCase(void)1060 	virtual ~ProgramStateReplaceSourceCase (void)
1061 	{
1062 	}
1063 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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 
programBinariesEqual(const ProgramBinary & first,const ProgramBinary & second)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 
ProgramBinaryCase(Context & context,const char * name,const char * desc)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 
~ProgramBinaryCase(void)1128 ProgramBinaryCase::~ProgramBinaryCase (void)
1129 {
1130 }
1131 
getBinaryFormats(std::vector<GLenum> & out)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 
isFormatSupported(const glw::GLenum format) const1147 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 
getProgramBinary(ProgramBinary & out,GLuint program)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 
loadProgramBinary(ProgramBinary & binary,GLuint program)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 
verifyProgramBinary(ProgramBinary & binary)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 
init(void)1191 void ProgramBinaryCase::init (void)
1192 {
1193 	getBinaryFormats(m_formats);
1194 }
1195 
iterate(void)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:
ProgramBinarySimpleCase(Context & context,const char * name,const char * desc)1222 	ProgramBinarySimpleCase (Context& context, const char* name, const char* desc)
1223 		: ProgramBinaryCase(context, name, desc)
1224 	{
1225 	}
1226 
~ProgramBinarySimpleCase(void)1227 	virtual ~ProgramBinarySimpleCase (void)
1228 	{
1229 	}
1230 
test(void)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:
ProgramBinaryUniformResetCase(Context & context,const char * name,const char * desc)1255 	ProgramBinaryUniformResetCase (Context& context, const char* name, const char* desc)
1256 		: ProgramBinaryCase	(context, name, desc)
1257 		, m_rnd				(deStringHash(name) ^ 0xf2b48c6a)
1258 	{
1259 	}
1260 
~ProgramBinaryUniformResetCase(void)1261 	virtual ~ProgramBinaryUniformResetCase (void)
1262 	{
1263 	}
1264 
getShaderSource(const glu::ShaderType shaderType) const1265 	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 
setUniformsRandom(glu::ShaderProgram & program)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 
verifyUniformInt(glu::ShaderProgram & program,const std::string & name)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 
verifyUniformFloat(glu::ShaderProgram & program,const std::string & name)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 
verifyUniformsReset(glu::ShaderProgram & program)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 
test(void)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);
~ProgramBinaryPersistenceCase(void)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 
ProgramBinaryPersistenceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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 
buildProgram(glu::Program & program,ShaderAllocator & shaders)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 
verify(glu::Program & program,const ProgramBinary & binary)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 
test(void)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>
addProgramBinaryPersistenceCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)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:
ProgramBinaryPersistenceDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1505 	ProgramBinaryPersistenceDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1506 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1507 	{
1508 	}
1509 
~ProgramBinaryPersistenceDetachShaderCase(void)1510 	virtual ~ProgramBinaryPersistenceDetachShaderCase (void)
1511 	{
1512 	}
1513 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1527 	ProgramBinaryPersistenceReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1528 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1529 	{
1530 	}
1531 
~ProgramBinaryPersistenceReattachShaderCase(void)1532 	virtual ~ProgramBinaryPersistenceReattachShaderCase (void)
1533 	{
1534 	}
1535 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1550 	ProgramBinaryPersistenceDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1551 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1552 	{
1553 	}
1554 
~ProgramBinaryPersistenceDeleteShaderCase(void)1555 	virtual ~ProgramBinaryPersistenceDeleteShaderCase (void)
1556 	{
1557 	}
1558 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1573 	ProgramBinaryPersistenceReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1574 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1575 	{
1576 	}
1577 
~ProgramBinaryPersistenceReplaceShaderCase(void)1578 	virtual ~ProgramBinaryPersistenceReplaceShaderCase (void)
1579 	{
1580 	}
1581 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1597 	ProgramBinaryPersistenceRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1598 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1599 	{
1600 	}
1601 
~ProgramBinaryPersistenceRecompileShaderCase(void)1602 	virtual ~ProgramBinaryPersistenceRecompileShaderCase (void)
1603 	{
1604 	}
1605 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1620 	ProgramBinaryPersistenceReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1621 		: ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1622 	{
1623 	}
1624 
~ProgramBinaryPersistenceReplaceSourceCase(void)1625 	virtual ~ProgramBinaryPersistenceReplaceSourceCase (void)
1626 	{
1627 	}
1628 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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 
ShaderApiTests(Context & context)1643 ShaderApiTests::ShaderApiTests (Context& context)
1644 	: TestCaseGroup(context, "shader_api", "Shader API Cases")
1645 {
1646 }
1647 
~ShaderApiTests(void)1648 ShaderApiTests::~ShaderApiTests (void)
1649 {
1650 }
1651 
init(void)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