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