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
49using namespace glw; // GL types
50
51namespace deqp
52{
53namespace gles3
54{
55namespace Functional
56{
57
58using tcu::TestLog;
59
60namespace
61{
62
63enum ShaderSourceCaseFlags
64{
65	CASE_EXPLICIT_SOURCE_LENGTHS	= 1,
66	CASE_RANDOM_NULL_TERMINATED		= 2
67};
68
69struct ShaderSources
70{
71	std::vector<std::string>	strings;
72	std::vector<int>			lengths;
73};
74
75// Simple shaders
76
77const 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
107void 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
120void 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
148void 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
188void 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
216class SourceGenerator
217{
218public:
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
225class ConstantShaderGenerator : public SourceGenerator
226{
227public:
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
235private:
236	de::Random	m_rnd;
237};
238
239std::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
264class ShaderAllocator
265{
266public:
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
279private:
280	const glu::RenderContext&				m_context;
281	SourceGenerator&						m_srcGen;
282	std::map<glu::ShaderType, glu::Shader*>	m_shaders;
283};
284
285ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator)
286	: m_context	(context)
287	, m_srcGen	(generator)
288{
289}
290
291ShaderAllocator::~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
298bool 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
306glu::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
318void 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
326void 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
339void 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
348void 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
363void 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
379class CreateShaderCase : public ApiCase
380{
381public:
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
397private:
398	const glu::ShaderType m_shaderType;
399};
400
401// Simple glCompileShader() case
402
403class CompileShaderCase : public ApiCase
404{
405public:
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
436private:
437	const glu::ShaderType m_shaderType;
438};
439
440// Base class for simple program API tests
441
442class SimpleProgramCase : public ApiCase
443{
444public:
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
502protected:
503	GLuint	m_vertShader;
504	GLuint	m_fragShader;
505	GLuint	m_program;
506};
507
508// glDeleteShader() case
509
510class DeleteShaderCase : public SimpleProgramCase
511{
512public:
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
552class LinkVertexFragmentCase : public SimpleProgramCase
553{
554public:
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
581class ShaderSourceReplaceCase : public ApiCase
582{
583public:
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
678private:
679	glu::ShaderType	m_shaderType;
680};
681
682// glShaderSource() split source case
683
684class ShaderSourceSplitCase : public ApiCase
685{
686public:
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
805private:
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
817class ProgramStateCase : public ApiCase
818{
819public:
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
830protected:
831	de::Random					m_rnd;
832	const glu::ShaderType		m_shaderType;
833};
834
835ProgramStateCase::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
843void 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
860void 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
884void 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
915namespace
916{
917
918template<class T>
919void 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
937class ProgramStateDetachShaderCase : public ProgramStateCase
938{
939public:
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
959class ProgramStateReattachShaderCase : public ProgramStateCase
960{
961public:
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
982class ProgramStateDeleteShaderCase : public ProgramStateCase
983{
984public:
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
1005class ProgramStateReplaceShaderCase : public ProgramStateCase
1006{
1007public:
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
1029class ProgramStateRecompileShaderCase : public ProgramStateCase
1030{
1031public:
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
1052class ProgramStateReplaceSourceCase : public ProgramStateCase
1053{
1054public:
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
1078namespace
1079{
1080
1081struct ProgramBinary
1082{
1083	GLenum					format;
1084	std::vector<deUint8>	data;
1085};
1086
1087bool 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
1099class ProgramBinaryCase : public TestCase, protected glu::CallLogWrapper
1100{
1101public:
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
1118protected:
1119	std::vector<GLenum>		m_formats;
1120};
1121
1122ProgramBinaryCase::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
1128ProgramBinaryCase::~ProgramBinaryCase (void)
1129{
1130}
1131
1132void 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
1147bool ProgramBinaryCase::isFormatSupported (const glw::GLenum format) const
1148{
1149	return (std::find(m_formats.begin(), m_formats.end(), format) != m_formats.end());
1150}
1151
1152void 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
1173void 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
1179void 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
1191void ProgramBinaryCase::init (void)
1192{
1193	getBinaryFormats(m_formats);
1194}
1195
1196tcu::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
1219class ProgramBinarySimpleCase : public ProgramBinaryCase
1220{
1221public:
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
1252class ProgramBinaryUniformResetCase : public ProgramBinaryCase
1253{
1254public:
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	}
1385private:
1386	de::Random	m_rnd;
1387};
1388
1389// Base class for program state persistence cases
1390
1391class ProgramBinaryPersistenceCase : public ProgramBinaryCase
1392{
1393public:
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
1404protected:
1405	de::Random				m_rnd;
1406	const glu::ShaderType	m_shaderType;
1407};
1408
1409ProgramBinaryPersistenceCase::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
1417void 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
1434void 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
1448void 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
1480namespace
1481{
1482
1483template<class T>
1484void 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
1502class ProgramBinaryPersistenceDetachShaderCase : public ProgramBinaryPersistenceCase
1503{
1504public:
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
1524class ProgramBinaryPersistenceReattachShaderCase : public ProgramBinaryPersistenceCase
1525{
1526public:
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
1547class ProgramBinaryPersistenceDeleteShaderCase : public ProgramBinaryPersistenceCase
1548{
1549public:
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
1570class ProgramBinaryPersistenceReplaceShaderCase : public ProgramBinaryPersistenceCase
1571{
1572public:
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
1594class ProgramBinaryPersistenceRecompileShaderCase : public ProgramBinaryPersistenceCase
1595{
1596public:
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
1617class ProgramBinaryPersistenceReplaceSourceCase : public ProgramBinaryPersistenceCase
1618{
1619public:
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
1643ShaderApiTests::ShaderApiTests (Context& context)
1644	: TestCaseGroup(context, "shader_api", "Shader API Cases")
1645{
1646}
1647
1648ShaderApiTests::~ShaderApiTests (void)
1649{
1650}
1651
1652void 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