1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) 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 Compiler test case.
22 *//*--------------------------------------------------------------------*/
23
24#include "glsShaderLibraryCase.hpp"
25
26#include "tcuTestLog.hpp"
27#include "tcuRenderTarget.hpp"
28
29#include "tcuStringTemplate.hpp"
30#include "gluShaderProgram.hpp"
31#include "gluPixelTransfer.hpp"
32#include "gluDrawUtil.hpp"
33#include "gluContextInfo.hpp"
34#include "gluStrUtil.hpp"
35
36#include "glwFunctions.hpp"
37#include "glwEnums.hpp"
38
39#include "deRandom.hpp"
40#include "deInt32.h"
41#include "deMath.h"
42#include "deString.h"
43#include "deStringUtil.hpp"
44#include "deSharedPtr.hpp"
45
46#include <map>
47#include <vector>
48#include <string>
49#include <sstream>
50
51using namespace std;
52using namespace tcu;
53using namespace glu;
54
55namespace deqp
56{
57namespace gls
58{
59namespace sl
60{
61
62enum
63{
64	VIEWPORT_WIDTH		= 128,
65	VIEWPORT_HEIGHT		= 128
66};
67
68static inline bool usesShaderInoutQualifiers (glu::GLSLVersion version)
69{
70	switch (version)
71	{
72		case glu::GLSL_VERSION_100_ES:
73		case glu::GLSL_VERSION_130:
74		case glu::GLSL_VERSION_140:
75		case glu::GLSL_VERSION_150:
76			return false;
77
78		default:
79			return true;
80	}
81}
82
83static inline bool supportsFragmentHighp (glu::GLSLVersion version)
84{
85	return version != glu::GLSL_VERSION_100_ES;
86}
87
88ShaderCase::ValueBlock::ValueBlock (void)
89	: arrayLength(0)
90{
91}
92
93ShaderCase::CaseRequirement::CaseRequirement (void)
94	: m_type						(REQUIREMENTTYPE_LAST)
95	, m_supportedExtensionNdx		(-1)
96	, m_effectiveShaderStageFlags	(-1)
97	, m_enumName					(-1)
98	, m_referenceValue				(-1)
99{
100}
101
102ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createAnyExtensionRequirement (const std::vector<std::string>& requirements, deUint32 effectiveShaderStageFlags)
103{
104	CaseRequirement retVal;
105
106	retVal.m_type = REQUIREMENTTYPE_EXTENSION;
107	retVal.m_extensions = requirements;
108	retVal.m_effectiveShaderStageFlags = effectiveShaderStageFlags;
109
110	return retVal;
111}
112
113ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createLimitRequirement (deUint32 enumName, int ref)
114{
115	CaseRequirement retVal;
116
117	retVal.m_type = REQUIREMENTTYPE_IMPLEMENTATION_LIMIT;
118	retVal.m_enumName = enumName;
119	retVal.m_referenceValue = ref;
120
121	return retVal;
122}
123
124ShaderCase::CaseRequirement ShaderCase::CaseRequirement::createFullGLSLES100SpecificationRequirement (void)
125{
126	CaseRequirement retVal;
127
128	retVal.m_type = REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC;
129
130	return retVal;
131}
132
133void ShaderCase::CaseRequirement::checkRequirements (glu::RenderContext& renderCtx, const glu::ContextInfo& contextInfo)
134{
135	DE_UNREF(renderCtx);
136
137	switch (m_type)
138	{
139		case REQUIREMENTTYPE_EXTENSION:
140		{
141			for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx)
142			{
143				if (contextInfo.isExtensionSupported(m_extensions[ndx].c_str()))
144				{
145					m_supportedExtensionNdx = ndx;
146					return;
147				}
148			}
149
150			// no extension(s). Make a nice output
151			{
152				std::ostringstream extensionList;
153
154				for (int ndx = 0; ndx < (int)m_extensions.size(); ++ndx)
155				{
156					if (!extensionList.str().empty())
157						extensionList << ", ";
158					extensionList << m_extensions[ndx];
159				}
160
161				if (m_extensions.size() == 1)
162					throw tcu::NotSupportedError("Test requires extension " + extensionList.str());
163				else
164					throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str());
165			}
166
167			// cannot be reached
168		}
169
170		case REQUIREMENTTYPE_IMPLEMENTATION_LIMIT:
171		{
172			const glw::Functions&	gl		= renderCtx.getFunctions();
173			glw::GLint				value	= 0;
174			glw::GLenum				error;
175
176			gl.getIntegerv(m_enumName, &value);
177			error = gl.getError();
178
179			if (error != GL_NO_ERROR)
180				throw tcu::TestError("Query for " + de::toString(glu::getGettableStateStr(m_enumName)) +  " generated " + de::toString(glu::getErrorStr(error)));
181
182			if (!(value > m_referenceValue))
183				throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(m_enumName)) + " (" + de::toString(value) + ") > " + de::toString(m_referenceValue));
184
185			return;
186		}
187
188		case REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC:
189		{
190			// cannot be queried
191			return;
192		}
193
194		default:
195			DE_ASSERT(false);
196	}
197}
198
199ShaderCase::ShaderCaseSpecification::ShaderCaseSpecification (void)
200	: expectResult	(EXPECT_LAST)
201	, targetVersion	(glu::GLSL_VERSION_LAST)
202	, caseType		(CASETYPE_COMPLETE)
203{
204}
205
206ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource)
207{
208	ShaderCaseSpecification retVal;
209	retVal.expectResult		= expectResult_;
210	retVal.targetVersion	= targetVersion_;
211	retVal.caseType			= CASETYPE_VERTEX_ONLY;
212	retVal.valueBlocks		= values;
213	retVal.vertexSources.push_back(sharedSource);
214	return retVal;
215}
216
217ShaderCase::ShaderCaseSpecification ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase (ExpectResult expectResult_, glu::GLSLVersion targetVersion_, const std::vector<ValueBlock>& values, const std::string& sharedSource)
218{
219	ShaderCaseSpecification retVal;
220	retVal.expectResult		= expectResult_;
221	retVal.targetVersion	= targetVersion_;
222	retVal.caseType			= CASETYPE_FRAGMENT_ONLY;
223	retVal.valueBlocks		= values;
224	retVal.fragmentSources.push_back(sharedSource);
225	return retVal;
226}
227
228class BeforeDrawValidator : public glu::DrawUtilCallback
229{
230public:
231	enum TargetType
232	{
233		TARGETTYPE_PROGRAM = 0,
234		TARGETTYPE_PIPELINE,
235
236		TARGETTYPE_LAST
237	};
238
239							BeforeDrawValidator	(const glw::Functions& gl, glw::GLuint target, TargetType targetType);
240
241	void					beforeDrawCall		(void);
242
243	const std::string&		getInfoLog			(void) const;
244	glw::GLint				getValidateStatus	(void) const;
245
246private:
247	const glw::Functions&	m_gl;
248	const glw::GLuint		m_target;
249	const TargetType		m_targetType;
250
251	glw::GLint				m_validateStatus;
252	std::string				m_logMessage;
253};
254
255BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType)
256	: m_gl				(gl)
257	, m_target			(target)
258	, m_targetType		(targetType)
259	, m_validateStatus	(-1)
260{
261	DE_ASSERT(targetType < TARGETTYPE_LAST);
262}
263
264void BeforeDrawValidator::beforeDrawCall (void)
265{
266	glw::GLint					bytesWritten	= 0;
267	glw::GLint					infoLogLength;
268	std::vector<glw::GLchar>	logBuffer;
269	int							stringLength;
270
271	// validate
272	if (m_targetType == TARGETTYPE_PROGRAM)
273		m_gl.validateProgram(m_target);
274	else if (m_targetType == TARGETTYPE_PIPELINE)
275		m_gl.validateProgramPipeline(m_target);
276	else
277		DE_ASSERT(false);
278
279	GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate");
280
281	// check status
282	m_validateStatus = -1;
283
284	if (m_targetType == TARGETTYPE_PROGRAM)
285		m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
286	else if (m_targetType == TARGETTYPE_PIPELINE)
287		m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
288	else
289		DE_ASSERT(false);
290
291	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status");
292	TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE);
293
294	// read log
295
296	infoLogLength = 0;
297
298	if (m_targetType == TARGETTYPE_PROGRAM)
299		m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
300	else if (m_targetType == TARGETTYPE_PIPELINE)
301		m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
302	else
303		DE_ASSERT(false);
304
305	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length");
306
307	if (infoLogLength <= 0)
308	{
309		m_logMessage.clear();
310		return;
311	}
312
313	logBuffer.resize(infoLogLength + 2, '0'); // +1 for zero terminator (infoLogLength should include it, but better play it safe), +1 to make sure buffer is always larger
314
315	if (m_targetType == TARGETTYPE_PROGRAM)
316		m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
317	else if (m_targetType == TARGETTYPE_PIPELINE)
318		m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
319	else
320		DE_ASSERT(false);
321
322	// just ignore bytesWritten to be safe, find the null terminator
323	stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin());
324	m_logMessage.assign(&logBuffer[0], stringLength);
325}
326
327const std::string& BeforeDrawValidator::getInfoLog (void) const
328{
329	return m_logMessage;
330}
331
332glw::GLint BeforeDrawValidator::getValidateStatus (void) const
333{
334	return m_validateStatus;
335}
336
337// ShaderCase.
338
339ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification)
340	: tcu::TestCase				(testCtx, name, description)
341	, m_renderCtx				(renderCtx)
342	, m_contextInfo				(contextInfo)
343	, m_caseType				(specification.caseType)
344	, m_expectResult			(specification.expectResult)
345	, m_targetVersion			(specification.targetVersion)
346	, m_separatePrograms		(false)
347	, m_valueBlocks				(specification.valueBlocks)
348{
349	if (m_caseType == CASETYPE_VERTEX_ONLY)
350	{
351		// case generated from "both" target, vertex case
352		DE_ASSERT(specification.vertexSources.size() == 1);
353		DE_ASSERT(specification.fragmentSources.empty());
354		DE_ASSERT(specification.tessCtrlSources.empty());
355		DE_ASSERT(specification.tessEvalSources.empty());
356		DE_ASSERT(specification.geometrySources.empty());
357	}
358	else if (m_caseType == CASETYPE_FRAGMENT_ONLY)
359	{
360		// case generated from "both" target, fragment case
361		DE_ASSERT(specification.vertexSources.empty());
362		DE_ASSERT(specification.fragmentSources.size() == 1);
363		DE_ASSERT(specification.tessCtrlSources.empty());
364		DE_ASSERT(specification.tessEvalSources.empty());
365		DE_ASSERT(specification.geometrySources.empty());
366	}
367
368	if (m_expectResult == EXPECT_BUILD_SUCCESSFUL)
369	{
370		// Shader is never executed. Presense of input/output values is likely an error
371		DE_ASSERT(m_valueBlocks.empty());
372	}
373
374	// single program object
375	{
376		ProgramObject program;
377		program.spec.requirements		= specification.requirements;
378		program.spec.vertexSources		= specification.vertexSources;
379		program.spec.fragmentSources	= specification.fragmentSources;
380		program.spec.tessCtrlSources	= specification.tessCtrlSources;
381		program.spec.tessEvalSources	= specification.tessEvalSources;
382		program.spec.geometrySources	= specification.geometrySources;
383
384		m_programs.push_back(program);
385	}
386}
387
388ShaderCase::ShaderCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const PipelineCaseSpecification& specification)
389	: tcu::TestCase				(testCtx, name, description)
390	, m_renderCtx				(renderCtx)
391	, m_contextInfo				(contextInfo)
392	, m_caseType				(specification.caseType)
393	, m_expectResult			(specification.expectResult)
394	, m_targetVersion			(specification.targetVersion)
395	, m_separatePrograms		(true)
396	, m_valueBlocks				(specification.valueBlocks)
397{
398	deUint32 totalActiveMask = 0;
399
400	DE_ASSERT(m_caseType == CASETYPE_COMPLETE);
401
402	// validate
403
404	for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx)
405	{
406		// program with an active stage must contain executable code for that stage
407		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_VERTEX))						== 0) || !specification.programs[pipelineProgramNdx].vertexSources.empty());
408		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_FRAGMENT))					== 0) || !specification.programs[pipelineProgramNdx].fragmentSources.empty());
409		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_CONTROL))		== 0) || !specification.programs[pipelineProgramNdx].tessCtrlSources.empty());
410		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION))	== 0) || !specification.programs[pipelineProgramNdx].tessEvalSources.empty());
411		DE_ASSERT(((specification.programs[pipelineProgramNdx].activeStageBits & (1 << glu::SHADERTYPE_GEOMETRY))					== 0) || !specification.programs[pipelineProgramNdx].geometrySources.empty());
412
413		// no two programs with with the same stage active
414		DE_ASSERT((totalActiveMask & specification.programs[pipelineProgramNdx].activeStageBits) == 0);
415		totalActiveMask |= specification.programs[pipelineProgramNdx].activeStageBits;
416	}
417
418	// create ProgramObjects
419
420	for (int pipelineProgramNdx = 0; pipelineProgramNdx < (int)specification.programs.size(); ++pipelineProgramNdx)
421	{
422		ProgramObject program;
423		program.spec = specification.programs[pipelineProgramNdx];
424		m_programs.push_back(program);
425	}
426}
427
428ShaderCase::~ShaderCase (void)
429{
430}
431
432void ShaderCase::init (void)
433{
434	// If no value blocks given, use an empty one.
435	if (m_valueBlocks.empty())
436		m_valueBlocks.push_back(ValueBlock());
437
438	// Use first value block to specialize shaders.
439	const ValueBlock& valueBlock = m_valueBlocks[0];
440
441	// \todo [2010-04-01 petri] Check that all value blocks have matching values.
442
443	// prepare programs
444	for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
445	{
446		// Check requirements
447		for (int ndx = 0; ndx < (int)m_programs[programNdx].spec.requirements.size(); ++ndx)
448			m_programs[programNdx].spec.requirements[ndx].checkRequirements(m_renderCtx, m_contextInfo);
449
450		// Generate specialized shader sources.
451		if (m_caseType == CASETYPE_COMPLETE)
452		{
453			// all shaders specified separately
454			specializeVertexShaders		(m_programs[programNdx].programSources,	m_programs[programNdx].spec.vertexSources,		valueBlock,	m_programs[programNdx].spec.requirements);
455			specializeFragmentShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.fragmentSources,	valueBlock,	m_programs[programNdx].spec.requirements);
456			specializeGeometryShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.geometrySources,	valueBlock,	m_programs[programNdx].spec.requirements);
457			specializeTessControlShaders(m_programs[programNdx].programSources,	m_programs[programNdx].spec.tessCtrlSources,	valueBlock,	m_programs[programNdx].spec.requirements);
458			specializeTessEvalShaders	(m_programs[programNdx].programSources,	m_programs[programNdx].spec.tessEvalSources,	valueBlock,	m_programs[programNdx].spec.requirements);
459		}
460		else if (m_caseType == CASETYPE_VERTEX_ONLY)
461		{
462			DE_ASSERT(m_programs.size() == 1);
463			DE_ASSERT(!m_separatePrograms);
464
465			// case generated from "both" target, vertex case
466			m_programs[0].programSources << glu::VertexSource(specializeVertexShader(m_programs[0].spec.vertexSources[0].c_str(), valueBlock));
467			m_programs[0].programSources << glu::FragmentSource(genFragmentShader(valueBlock));
468		}
469		else if (m_caseType == CASETYPE_FRAGMENT_ONLY)
470		{
471			DE_ASSERT(m_programs.size() == 1);
472			DE_ASSERT(!m_separatePrograms);
473
474			// case generated from "both" target, fragment case
475			m_programs[0].programSources << glu::VertexSource(genVertexShader(valueBlock));
476			m_programs[0].programSources << glu::FragmentSource(specializeFragmentShader(m_programs[0].spec.fragmentSources[0].c_str(), valueBlock));
477		}
478
479		m_programs[programNdx].programSources << glu::ProgramSeparable(m_separatePrograms);
480	}
481
482	// log the expected result
483	switch (m_expectResult)
484	{
485		case EXPECT_PASS:
486			// Don't write anything
487			break;
488
489		case EXPECT_COMPILE_FAIL:
490			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
491			break;
492
493		case EXPECT_LINK_FAIL:
494			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
495			break;
496
497		case EXPECT_COMPILE_LINK_FAIL:
498			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
499			break;
500
501		case EXPECT_VALIDATION_FAIL:
502			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
503			break;
504
505		case EXPECT_BUILD_SUCCESSFUL:
506			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
507			break;
508
509		default:
510			DE_ASSERT(false);
511			break;
512	}
513
514	// sanity of arguments
515
516	if (anyProgramRequiresFullGLSLES100Specification())
517	{
518		// makes only sense in tests where shader compiles
519		DE_ASSERT(m_expectResult == EXPECT_PASS				||
520				  m_expectResult == EXPECT_VALIDATION_FAIL	||
521				  m_expectResult == EXPECT_BUILD_SUCCESSFUL);
522
523		// only makes sense for ES 100 programs
524		DE_ASSERT(m_targetVersion == glu::GLSL_VERSION_100_ES);
525	}
526}
527
528static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const ShaderCase::Value& val, int arrayNdx, tcu::TestLog& log)
529{
530	bool foundAnyMatch = false;
531
532	for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
533	{
534		const int scalarSize	= getDataTypeScalarSize(val.dataType);
535		const int loc			= gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
536		const int elemNdx		= (val.arrayLength == 1) ? (0) : (arrayNdx * scalarSize);
537
538		if (loc == -1)
539			continue;
540
541		foundAnyMatch = true;
542
543		DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLfloat));
544		DE_STATIC_ASSERT(sizeof(ShaderCase::Value::Element) == sizeof(glw::GLint));
545
546		gl.useProgram(pipelinePrograms[programNdx]);
547
548		switch (val.dataType)
549		{
550			case TYPE_FLOAT:		gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);						break;
551			case TYPE_FLOAT_VEC2:	gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);						break;
552			case TYPE_FLOAT_VEC3:	gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);						break;
553			case TYPE_FLOAT_VEC4:	gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);						break;
554			case TYPE_FLOAT_MAT2:	gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
555			case TYPE_FLOAT_MAT3:	gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
556			case TYPE_FLOAT_MAT4:	gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
557			case TYPE_INT:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
558			case TYPE_INT_VEC2:		gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
559			case TYPE_INT_VEC3:		gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
560			case TYPE_INT_VEC4:		gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
561			case TYPE_BOOL:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
562			case TYPE_BOOL_VEC2:	gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
563			case TYPE_BOOL_VEC3:	gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
564			case TYPE_BOOL_VEC4:	gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
565			case TYPE_UINT:			gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
566			case TYPE_UINT_VEC2:	gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
567			case TYPE_UINT_VEC3:	gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
568			case TYPE_UINT_VEC4:	gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
569			case TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
570			case TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
571			case TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
572			case TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
573			case TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
574			case TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
575
576			case TYPE_SAMPLER_2D:
577			case TYPE_SAMPLER_CUBE:
578				DE_ASSERT(!"implement!");
579				break;
580
581			default:
582				DE_ASSERT(false);
583		}
584	}
585
586	if (!foundAnyMatch)
587		log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
588}
589
590bool ShaderCase::isTessellationPresent (void) const
591{
592	if (m_separatePrograms)
593	{
594		const deUint32 tessellationBits =	(1 << glu::SHADERTYPE_TESSELLATION_CONTROL)		|
595											(1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
596
597		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
598			if (m_programs[programNdx].spec.activeStageBits & tessellationBits)
599				return true;
600		return false;
601	}
602	else
603		return	!m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
604				!m_programs[0].programSources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
605}
606
607bool ShaderCase::anyProgramRequiresFullGLSLES100Specification (void) const
608{
609	for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
610	for (int requirementNdx = 0; requirementNdx < (int)m_programs[programNdx].spec.requirements.size(); ++requirementNdx)
611	{
612		if (m_programs[programNdx].spec.requirements[requirementNdx].getType() == CaseRequirement::REQUIREMENTTYPE_FULL_GLSL_ES_100_SPEC)
613			return true;
614	}
615	return false;
616}
617
618bool ShaderCase::checkPixels (Surface& surface, int minX, int maxX, int minY, int maxY)
619{
620	TestLog&	log				= m_testCtx.getLog();
621	bool		allWhite		= true;
622	bool		allBlack		= true;
623	bool		anyUnexpected	= false;
624
625	DE_ASSERT((maxX > minX) && (maxY > minY));
626
627	for (int y = minY; y <= maxY; y++)
628	{
629		for (int x = minX; x <= maxX; x++)
630		{
631			RGBA		pixel		 = surface.getPixel(x, y);
632			// Note: we really do not want to involve alpha in the check comparison
633			// \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
634			bool		isWhite		 = (pixel.getRed() == 255) && (pixel.getGreen() == 255) && (pixel.getBlue() == 255);
635			bool		isBlack		 = (pixel.getRed() == 0) && (pixel.getGreen() == 0) && (pixel.getBlue() == 0);
636
637			allWhite		= allWhite && isWhite;
638			allBlack		= allBlack && isBlack;
639			anyUnexpected	= anyUnexpected || (!isWhite && !isBlack);
640		}
641	}
642
643	if (!allWhite)
644	{
645		if (anyUnexpected)
646			log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
647		else if (!allBlack)
648			log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
649
650		return false;
651	}
652	return true;
653}
654
655bool ShaderCase::execute (void)
656{
657	const float										quadSize				= 1.0f;
658	static const float								s_positions[4*4]		=
659	{
660		-quadSize, -quadSize, 0.0f, 1.0f,
661		-quadSize, +quadSize, 0.0f, 1.0f,
662		+quadSize, -quadSize, 0.0f, 1.0f,
663		+quadSize, +quadSize, 0.0f, 1.0f
664	};
665
666	static const deUint16							s_indices[2*3]			=
667	{
668		0, 1, 2,
669		1, 3, 2
670	};
671
672	TestLog&										log						= m_testCtx.getLog();
673	const glw::Functions&							gl						= m_renderCtx.getFunctions();
674
675	// Compute viewport.
676	const tcu::RenderTarget&						renderTarget			= m_renderCtx.getRenderTarget();
677	de::Random										rnd						(deStringHash(getName()));
678	const int										width					= deMin32(renderTarget.getWidth(),	VIEWPORT_WIDTH);
679	const int										height					= deMin32(renderTarget.getHeight(),	VIEWPORT_HEIGHT);
680	const int										viewportX				= rnd.getInt(0, renderTarget.getWidth()  - width);
681	const int										viewportY				= rnd.getInt(0, renderTarget.getHeight() - height);
682	const int										numVerticesPerDraw		= 4;
683	const bool										tessellationPresent		= isTessellationPresent();
684	const bool										requiresFullGLSLES100	= anyProgramRequiresFullGLSLES100Specification();
685
686	bool											allCompilesOk			= true;
687	bool											allLinksOk				= true;
688	const char*										failReason				= DE_NULL;
689
690	deUint32										vertexProgramID			= -1;
691	std::vector<deUint32>							pipelineProgramIDs;
692	std::vector<de::SharedPtr<glu::ShaderProgram> >	programs;
693	de::SharedPtr<glu::ProgramPipeline>				programPipeline;
694
695	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
696
697	if (!m_separatePrograms)
698	{
699		de::SharedPtr<glu::ShaderProgram>	program		(new glu::ShaderProgram(m_renderCtx, m_programs[0].programSources));
700
701		vertexProgramID = program->getProgram();
702		pipelineProgramIDs.push_back(program->getProgram());
703		programs.push_back(program);
704
705		// Check that compile/link results are what we expect.
706
707		DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
708		for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
709			if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
710				allCompilesOk = false;
711
712		if (!program->getProgramInfo().linkOk)
713			allLinksOk = false;
714
715		log << *program;
716	}
717	else
718	{
719		// Separate programs
720		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
721		{
722			de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, m_programs[programNdx].programSources));
723
724			if (m_programs[programNdx].spec.activeStageBits & (1 << glu::SHADERTYPE_VERTEX))
725				vertexProgramID = program->getProgram();
726
727			pipelineProgramIDs.push_back(program->getProgram());
728			programs.push_back(program);
729
730			// Check that compile/link results are what we expect.
731
732			DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
733			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
734				if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
735					allCompilesOk = false;
736
737			if (!program->getProgramInfo().linkOk)
738				allLinksOk = false;
739
740			// Log program and active stages
741			{
742				const tcu::ScopedLogSection	section		(log, "Program", "Program " + de::toString(programNdx+1));
743				tcu::MessageBuilder			builder		(&log);
744				bool						firstStage	= true;
745
746				builder << "Pipeline uses stages: ";
747				for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
748				{
749					if (m_programs[programNdx].spec.activeStageBits & (1 << stage))
750					{
751						if (!firstStage)
752							builder << ", ";
753						builder << glu::getShaderTypeName((glu::ShaderType)stage);
754						firstStage = true;
755					}
756				}
757				builder << tcu::TestLog::EndMessage;
758
759				log << *program;
760			}
761		}
762	}
763
764	switch (m_expectResult)
765	{
766		case EXPECT_PASS:
767		case EXPECT_VALIDATION_FAIL:
768		case EXPECT_BUILD_SUCCESSFUL:
769			if (!allCompilesOk)
770				failReason = "expected shaders to compile and link properly, but failed to compile.";
771			else if (!allLinksOk)
772				failReason = "expected shaders to compile and link properly, but failed to link.";
773			break;
774
775		case EXPECT_COMPILE_FAIL:
776			if (allCompilesOk && !allLinksOk)
777				failReason = "expected compilation to fail, but shaders compiled and link failed.";
778			else if (allCompilesOk)
779				failReason = "expected compilation to fail, but shaders compiled correctly.";
780			break;
781
782		case EXPECT_LINK_FAIL:
783			if (!allCompilesOk)
784				failReason = "expected linking to fail, but unable to compile.";
785			else if (allLinksOk)
786				failReason = "expected linking to fail, but passed.";
787			break;
788
789		case EXPECT_COMPILE_LINK_FAIL:
790			if (allCompilesOk && allLinksOk)
791				failReason = "expected compile or link to fail, but passed.";
792			break;
793
794		default:
795			DE_ASSERT(false);
796			return false;
797	}
798
799	if (failReason != DE_NULL)
800	{
801		// \todo [2010-06-07 petri] These should be handled in the test case?
802		log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
803
804		if (requiresFullGLSLES100)
805		{
806			log	<< TestLog::Message
807				<< "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
808				<< TestLog::EndMessage;
809
810			if (allCompilesOk && !allLinksOk)
811			{
812				// Used features are detectable at compile time. If implementation parses shader
813				// at link time, report it as quality warning.
814				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
815			}
816			else
817				m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
818		}
819		else if (m_expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
820		{
821			// If implementation parses shader at link time, report it as quality warning.
822			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
823		}
824		else
825			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
826		return false;
827	}
828
829	// Return if shader is not intended to be run
830	if (m_expectResult == EXPECT_COMPILE_FAIL		||
831		m_expectResult == EXPECT_COMPILE_LINK_FAIL	||
832		m_expectResult == EXPECT_LINK_FAIL			||
833		m_expectResult == EXPECT_BUILD_SUCCESSFUL)
834		return true;
835
836	// Setup viewport.
837	gl.viewport(viewportX, viewportY, width, height);
838
839	if (m_separatePrograms)
840	{
841		programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
842
843		// Setup pipeline
844		gl.bindProgramPipeline(programPipeline->getPipeline());
845		for (int programNdx = 0; programNdx < (int)m_programs.size(); ++programNdx)
846		{
847			deUint32 shaderFlags = 0;
848			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
849				if (m_programs[programNdx].spec.activeStageBits & (1 << stage))
850					shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
851
852			programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
853		}
854
855		programPipeline->activeShaderProgram(vertexProgramID);
856		GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
857	}
858	else
859	{
860		// Start using program
861		gl.useProgram(vertexProgramID);
862		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
863	}
864
865	// Fetch location for positions positions.
866	int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
867	if (positionLoc == -1)
868	{
869		string errStr = string("no location found for attribute 'dEQP_Position'");
870		TCU_FAIL(errStr.c_str());
871	}
872
873	// Iterate all value blocks.
874	for (int blockNdx = 0; blockNdx < (int)m_valueBlocks.size(); blockNdx++)
875	{
876		const ValueBlock&	valueBlock		= m_valueBlocks[blockNdx];
877
878		// always render at least one pass even if there is no input/output data
879		const int			numRenderPasses	= (valueBlock.arrayLength == 0) ? (1) : (valueBlock.arrayLength);
880
881		// Iterate all array sub-cases.
882		for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
883		{
884			int							numValues			= (int)valueBlock.values.size();
885			vector<VertexArrayBinding>	vertexArrays;
886			int							attribValueNdx		= 0;
887			vector<vector<float> >		attribValues		(numValues);
888			glw::GLenum					postDrawError;
889			BeforeDrawValidator			beforeDrawValidator	(gl,
890															 (m_separatePrograms) ? (programPipeline->getPipeline())			: (vertexProgramID),
891															 (m_separatePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE)	: (BeforeDrawValidator::TARGETTYPE_PROGRAM));
892
893			vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
894
895			// Collect VA pointer for inputs
896			for (int valNdx = 0; valNdx < numValues; valNdx++)
897			{
898				const ShaderCase::Value&	val			= valueBlock.values[valNdx];
899				const char* const			valueName	= val.valueName.c_str();
900				const DataType				dataType	= val.dataType;
901				const int					scalarSize	= getDataTypeScalarSize(val.dataType);
902
903				if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
904				{
905					// Replicate values four times.
906					std::vector<float>& scalars = attribValues[attribValueNdx++];
907					scalars.resize(numVerticesPerDraw * scalarSize);
908					if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
909					{
910						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
911							for (int ndx = 0; ndx < scalarSize; ndx++)
912								scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
913					}
914					else
915					{
916						// convert to floats.
917						for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
918						{
919							for (int ndx = 0; ndx < scalarSize; ndx++)
920							{
921								float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
922								DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
923								scalars[repNdx*scalarSize + ndx] = v;
924							}
925						}
926					}
927
928					// Attribute name prefix.
929					string attribPrefix = "";
930					// \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
931					if ((m_caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
932						attribPrefix = "a_";
933
934					// Input always given as attribute.
935					string attribName = attribPrefix + valueName;
936					int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
937					if (attribLoc == -1)
938					{
939						log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
940						continue;
941					}
942
943					if (isDataTypeMatrix(dataType))
944					{
945						int numCols = getDataTypeMatrixNumColumns(dataType);
946						int numRows = getDataTypeMatrixNumRows(dataType);
947						DE_ASSERT(scalarSize == numCols*numRows);
948
949						for (int i = 0; i < numCols; i++)
950							vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*sizeof(float), &scalars[i * numRows]));
951					}
952					else
953					{
954						DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
955						vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
956					}
957
958					GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
959				}
960			}
961
962			GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
963
964			// set uniform values for outputs (refs).
965			for (int valNdx = 0; valNdx < numValues; valNdx++)
966			{
967				const ShaderCase::Value&	val			= valueBlock.values[valNdx];
968				const char* const			valueName	= val.valueName.c_str();
969
970				if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
971				{
972					// Set reference value.
973					string refName = string("ref_") + valueName;
974					setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
975					GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
976				}
977				else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM)
978				{
979					setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
980					GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
981				}
982			}
983
984			// Clear.
985			gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
986			gl.clear(GL_COLOR_BUFFER_BIT);
987			GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
988
989			// Use program or pipeline
990			if (m_separatePrograms)
991				gl.useProgram(0);
992			else
993				gl.useProgram(vertexProgramID);
994
995			// Draw.
996			if (tessellationPresent)
997			{
998				gl.patchParameteri(GL_PATCH_VERTICES, 3);
999				GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
1000			}
1001
1002			draw(m_renderCtx,
1003				 vertexProgramID,
1004				 (int)vertexArrays.size(),
1005				 &vertexArrays[0],
1006				 (tessellationPresent) ?
1007					(pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
1008					(pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
1009				 (m_expectResult == EXPECT_VALIDATION_FAIL) ?
1010					(&beforeDrawValidator) :
1011					(DE_NULL));
1012
1013			postDrawError = gl.getError();
1014
1015			if (m_expectResult == EXPECT_PASS)
1016			{
1017				// Read back results.
1018				Surface			surface			(width, height);
1019				const float		w				= s_positions[3];
1020				const int		minY			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * height + 1.0f);
1021				const int		maxY			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * height - 0.5f);
1022				const int		minX			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * width + 1.0f);
1023				const int		maxX			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * width - 0.5f);
1024
1025				GLU_EXPECT_NO_ERROR(postDrawError, "draw");
1026
1027				glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
1028				GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
1029
1030				if (!checkPixels(surface, minX, maxX, minY, maxY))
1031				{
1032					log << TestLog::Message << "INCORRECT RESULT for (value block " << (blockNdx+1) << " of " <<  (int)m_valueBlocks.size()
1033											<< ", sub-case " << arrayNdx+1 << " of " << valueBlock.arrayLength << "):"
1034						<< TestLog::EndMessage;
1035
1036					log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
1037					dumpValues(valueBlock, arrayNdx);
1038
1039					// Dump image on failure.
1040					log << TestLog::Image("Result", "Rendered result image", surface);
1041
1042					gl.useProgram(0);
1043					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1044					return false;
1045				}
1046			}
1047			else if (m_expectResult == EXPECT_VALIDATION_FAIL)
1048			{
1049				log	<< TestLog::Message
1050					<< "Draw call generated error: "
1051					<< glu::getErrorStr(postDrawError) << " "
1052					<< ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
1053					<< "Validate status: "
1054					<< glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
1055					<< ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
1056					<< "Info log: "
1057					<< ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
1058					<< TestLog::EndMessage;
1059
1060				// test result
1061
1062				if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
1063				{
1064					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
1065					return false;
1066				}
1067
1068				if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
1069				{
1070					if (postDrawError == GL_NO_ERROR)
1071						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
1072					else if (postDrawError == GL_INVALID_OPERATION)
1073						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
1074					else
1075						DE_ASSERT(false);
1076					return false;
1077				}
1078				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
1079				{
1080					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
1081					return false;
1082				}
1083				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
1084				{
1085					// Validation does not depend on input values, no need to test all values
1086					return true;
1087				}
1088				else
1089					DE_ASSERT(false);
1090			}
1091			else
1092				DE_ASSERT(false);
1093		}
1094	}
1095
1096	gl.useProgram(0);
1097	if (m_separatePrograms)
1098		gl.bindProgramPipeline(0);
1099
1100	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
1101	return true;
1102}
1103
1104TestCase::IterateResult ShaderCase::iterate (void)
1105{
1106	// Initialize state to pass.
1107	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1108
1109	bool executeOk = execute();
1110
1111	DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
1112	DE_UNREF(executeOk);
1113	return TestCase::STOP;
1114}
1115
1116static void generateExtensionStatements (std::ostringstream& buf, const std::vector<ShaderCase::CaseRequirement>& requirements, glu::ShaderType type)
1117{
1118	for (int ndx = 0; ndx < (int)requirements.size(); ++ndx)
1119		if (requirements[ndx].getType() == ShaderCase::CaseRequirement::REQUIREMENTTYPE_EXTENSION &&
1120			(requirements[ndx].getAffectedExtensionStageFlags() & (1 << (deUint32)type)) != 0)
1121			buf << "#extension " << requirements[ndx].getSupportedExtension() << " : require\n";
1122}
1123
1124// Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations
1125static std::string injectExtensionRequirements (const std::string& baseCode, glu::ShaderType shaderType, const std::vector<ShaderCase::CaseRequirement>& requirements)
1126{
1127	std::istringstream	baseCodeBuf(baseCode);
1128	std::ostringstream	resultBuf;
1129	std::string			line;
1130	bool				firstNonPreprocessorLine = true;
1131	std::ostringstream	extensions;
1132
1133	generateExtensionStatements(extensions, requirements, shaderType);
1134
1135	// skip if no requirements
1136	if (extensions.str().empty())
1137		return baseCode;
1138
1139	while (std::getline(baseCodeBuf, line))
1140	{
1141		// begins with '#'?
1142		const std::string::size_type	firstNonWhitespace		= line.find_first_not_of("\t ");
1143		const bool						isPreprocessorDirective	= (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#');
1144
1145		// Inject #extensions
1146		if (!isPreprocessorDirective && firstNonPreprocessorLine)
1147		{
1148			firstNonPreprocessorLine = false;
1149			resultBuf << extensions.str();
1150		}
1151
1152		resultBuf << line << "\n";
1153	}
1154
1155	return resultBuf.str();
1156}
1157
1158// This functions builds a matching vertex shader for a 'both' case, when
1159// the fragment shader is being tested.
1160// We need to build attributes and varyings for each 'input'.
1161string ShaderCase::genVertexShader (const ValueBlock& valueBlock) const
1162{
1163	ostringstream	res;
1164	const bool		usesInout	= usesShaderInoutQualifiers(m_targetVersion);
1165	const char*		vtxIn		= usesInout ? "in"	: "attribute";
1166	const char*		vtxOut		= usesInout ? "out"	: "varying";
1167
1168	res << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
1169
1170	// Declarations (position + attribute/varying for each input).
1171	res << "precision highp float;\n";
1172	res << "precision highp int;\n";
1173	res << "\n";
1174	res << vtxIn << " highp vec4 dEQP_Position;\n";
1175	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1176	{
1177		const ShaderCase::Value& val = valueBlock.values[ndx];
1178		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1179		{
1180			DataType	floatType	= getDataTypeFloatScalars(val.dataType);
1181			const char*	typeStr		= getDataTypeName(floatType);
1182			res << vtxIn << " " << typeStr << " a_" << val.valueName << ";\n";
1183
1184			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1185				res << vtxOut << " " << typeStr << " " << val.valueName << ";\n";
1186			else
1187				res << vtxOut << " " << typeStr << " v_" << val.valueName << ";\n";
1188		}
1189	}
1190	res << "\n";
1191
1192	// Main function.
1193	// - gl_Position = dEQP_Position;
1194	// - for each input: write attribute directly to varying
1195	res << "void main()\n";
1196	res << "{\n";
1197	res << "	gl_Position = dEQP_Position;\n";
1198	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1199	{
1200		const ShaderCase::Value& val = valueBlock.values[ndx];
1201		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1202		{
1203			const string& name = val.valueName;
1204			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1205				res << "	" << name << " = a_" << name << ";\n";
1206			else
1207				res << "	v_" << name << " = a_" << name << ";\n";
1208		}
1209	}
1210
1211	res << "}\n";
1212	return res.str();
1213}
1214
1215static void genCompareFunctions (ostringstream& stream, const ShaderCase::ValueBlock& valueBlock, bool useFloatTypes)
1216{
1217	bool cmpTypeFound[TYPE_LAST];
1218	for (int i = 0; i < TYPE_LAST; i++)
1219		cmpTypeFound[i] = false;
1220
1221	for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
1222	{
1223		const ShaderCase::Value& val = valueBlock.values[valueNdx];
1224		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1225			cmpTypeFound[(int)val.dataType] = true;
1226	}
1227
1228	if (useFloatTypes)
1229	{
1230		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
1231		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
1232		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
1233		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
1234		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (float a, int b)  { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n";
1235		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
1236		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
1237		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
1238		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n";
1239		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
1240		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
1241		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
1242	}
1243	else
1244	{
1245		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (bool a, bool b)   { return (a == b); }\n";
1246		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
1247		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
1248		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
1249		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (int a, int b)     { return (a == b); }\n";
1250		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
1251		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
1252		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
1253		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (uint a, uint b)   { return (a == b); }\n";
1254		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
1255		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
1256		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
1257	}
1258
1259	if (cmpTypeFound[TYPE_FLOAT])		stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
1260	if (cmpTypeFound[TYPE_FLOAT_VEC2])	stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1261	if (cmpTypeFound[TYPE_FLOAT_VEC3])	stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1262	if (cmpTypeFound[TYPE_FLOAT_VEC4])	stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1263
1264	if (cmpTypeFound[TYPE_FLOAT_MAT2])		stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1265	if (cmpTypeFound[TYPE_FLOAT_MAT2X3])	stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1266	if (cmpTypeFound[TYPE_FLOAT_MAT2X4])	stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1267	if (cmpTypeFound[TYPE_FLOAT_MAT3X2])	stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1268	if (cmpTypeFound[TYPE_FLOAT_MAT3])		stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1269	if (cmpTypeFound[TYPE_FLOAT_MAT3X4])	stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1270	if (cmpTypeFound[TYPE_FLOAT_MAT4X2])	stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
1271	if (cmpTypeFound[TYPE_FLOAT_MAT4X3])	stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
1272	if (cmpTypeFound[TYPE_FLOAT_MAT4])		stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";
1273}
1274
1275static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ShaderCase::ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName)
1276{
1277	bool isFirstOutput = true;
1278
1279	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1280	{
1281		const ShaderCase::Value&	val			= valueBlock.values[ndx];
1282		const char*					valueName	= val.valueName.c_str();
1283
1284		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1285		{
1286			// Check if we're only interested in one variable (then skip if not the right one).
1287			if (checkVarName && !deStringEqual(valueName, checkVarName))
1288				continue;
1289
1290			// Prefix.
1291			if (isFirstOutput)
1292			{
1293				output << "bool RES = ";
1294				isFirstOutput = false;
1295			}
1296			else
1297				output << "RES = RES && ";
1298
1299			// Generate actual comparison.
1300			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1301				output << "isOk(" << valueName << ", ref_" << valueName << ", 0.05);\n";
1302			else
1303				output << "isOk(" << nonFloatNamePrefix << valueName << ", ref_" << valueName << ");\n";
1304		}
1305		// \note Uniforms are already declared in shader.
1306	}
1307
1308	if (isFirstOutput)
1309		output << dstVec4Var << " = vec4(1.0);\n";	// \todo [petri] Should we give warning if not expect-failure case?
1310	else
1311		output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
1312}
1313
1314string ShaderCase::genFragmentShader (const ValueBlock& valueBlock) const
1315{
1316	ostringstream	shader;
1317	const bool		usesInout		= usesShaderInoutQualifiers(m_targetVersion);
1318	const bool		customColorOut	= usesInout;
1319	const char*		fragIn			= usesInout ? "in" : "varying";
1320	const char*		prec			= supportsFragmentHighp(m_targetVersion) ? "highp" : "mediump";
1321
1322	shader << glu::getGLSLVersionDeclaration(m_targetVersion) << "\n";
1323
1324	shader << "precision " << prec << " float;\n";
1325	shader << "precision " << prec << " int;\n";
1326	shader << "\n";
1327
1328	if (customColorOut)
1329	{
1330		shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1331		shader << "\n";
1332	}
1333
1334	genCompareFunctions(shader, valueBlock, true);
1335	shader << "\n";
1336
1337	// Declarations (varying, reference for each output).
1338	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1339	{
1340		const ShaderCase::Value& val = valueBlock.values[ndx];
1341		DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1342		const char*	floatTypeStr	= getDataTypeName(floatType);
1343		const char*	refTypeStr		= getDataTypeName(val.dataType);
1344
1345		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1346		{
1347			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1348				shader << fragIn << " " << floatTypeStr << " " << val.valueName << ";\n";
1349			else
1350				shader << fragIn << " " << floatTypeStr << " v_" << val.valueName << ";\n";
1351
1352			shader << "uniform " << refTypeStr << " ref_" << val.valueName << ";\n";
1353		}
1354	}
1355
1356	shader << "\n";
1357	shader << "void main()\n";
1358	shader << "{\n";
1359
1360	shader << "	";
1361	genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", valueBlock, "v_", DE_NULL);
1362
1363	shader << "}\n";
1364	return shader.str();
1365}
1366
1367// Specialize a shader for the vertex shader test case.
1368string ShaderCase::specializeVertexShader (const char* src, const ValueBlock& valueBlock) const
1369{
1370	ostringstream	decl;
1371	ostringstream	setup;
1372	ostringstream	output;
1373	const bool		usesInout	= usesShaderInoutQualifiers(m_targetVersion);
1374	const char*		vtxIn		= usesInout ? "in"	: "attribute";
1375	const char*		vtxOut		= usesInout ? "out"	: "varying";
1376
1377	// generated from "both" case
1378	DE_ASSERT(m_caseType == CASETYPE_VERTEX_ONLY);
1379
1380	// Output (write out position).
1381	output << "gl_Position = dEQP_Position;\n";
1382
1383	// Declarations (position + attribute for each input, varying for each output).
1384	decl << vtxIn << " highp vec4 dEQP_Position;\n";
1385	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1386	{
1387		const ShaderCase::Value& val = valueBlock.values[ndx];
1388		const char*	valueName		= val.valueName.c_str();
1389		DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1390		const char*	floatTypeStr	= getDataTypeName(floatType);
1391		const char*	refTypeStr		= getDataTypeName(val.dataType);
1392
1393		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1394		{
1395			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1396			{
1397				decl << vtxIn << " " << floatTypeStr << " " << valueName << ";\n";
1398			}
1399			else
1400			{
1401				decl << vtxIn << " " << floatTypeStr << " a_" << valueName << ";\n";
1402				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(a_" << valueName << ");\n";
1403			}
1404		}
1405		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1406		{
1407			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1408				decl << vtxOut << " " << floatTypeStr << " " << valueName << ";\n";
1409			else
1410			{
1411				decl << vtxOut << " " << floatTypeStr << " v_" << valueName << ";\n";
1412				decl << refTypeStr << " " << valueName << ";\n";
1413
1414				output << "v_" << valueName << " = " << floatTypeStr << "(" << valueName << ");\n";
1415			}
1416		}
1417	}
1418
1419	// Shader specialization.
1420	map<string, string> params;
1421	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
1422	params.insert(pair<string, string>("SETUP", setup.str()));
1423	params.insert(pair<string, string>("OUTPUT", output.str()));
1424	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
1425
1426	StringTemplate	tmpl	(src);
1427	const string	baseSrc	= tmpl.specialize(params);
1428	const string	withExt	= injectExtensionRequirements(baseSrc, SHADERTYPE_VERTEX, m_programs[0].spec.requirements);
1429
1430	return withExt;
1431}
1432
1433// Specialize a shader for the fragment shader test case.
1434string ShaderCase::specializeFragmentShader (const char* src, const ValueBlock& valueBlock) const
1435{
1436	ostringstream	decl;
1437	ostringstream	setup;
1438	ostringstream	output;
1439
1440	const bool		usesInout		= usesShaderInoutQualifiers(m_targetVersion);
1441	const bool		customColorOut	= usesInout;
1442	const char*		fragIn			= usesInout			? "in"				: "varying";
1443	const char*		fragColor		= customColorOut	? "dEQP_FragColor"	: "gl_FragColor";
1444
1445	// generated from "both" case
1446	DE_ASSERT(m_caseType == CASETYPE_FRAGMENT_ONLY);
1447
1448	genCompareFunctions(decl, valueBlock, false);
1449	genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
1450
1451	if (customColorOut)
1452		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1453
1454	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1455	{
1456		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1457		const char*					valueName		= val.valueName.c_str();
1458		DataType					floatType		= getDataTypeFloatScalars(val.dataType);
1459		const char*					floatTypeStr	= getDataTypeName(floatType);
1460		const char*					refTypeStr		= getDataTypeName(val.dataType);
1461
1462		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1463		{
1464			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1465				decl << fragIn << " " << floatTypeStr << " " << valueName << ";\n";
1466			else
1467			{
1468				decl << fragIn << " " << floatTypeStr << " v_" << valueName << ";\n";
1469				std::string offset = isDataTypeIntOrIVec(val.dataType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
1470				setup << refTypeStr << " " << valueName << " = " << refTypeStr << "(v_" << valueName << offset << ");\n";
1471			}
1472		}
1473		else if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1474		{
1475			decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
1476			decl << refTypeStr << " " << valueName << ";\n";
1477		}
1478	}
1479
1480	/* \todo [2010-04-01 petri] Check all outputs. */
1481
1482	// Shader specialization.
1483	map<string, string> params;
1484	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
1485	params.insert(pair<string, string>("SETUP", setup.str()));
1486	params.insert(pair<string, string>("OUTPUT", output.str()));
1487	params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
1488
1489	StringTemplate	tmpl	(src);
1490	const string	baseSrc	= tmpl.specialize(params);
1491	const string	withExt	= injectExtensionRequirements(baseSrc, SHADERTYPE_FRAGMENT, m_programs[0].spec.requirements);
1492
1493	return withExt;
1494}
1495
1496static map<string, string> generateVertexSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1497{
1498	const bool				usesInout	= usesShaderInoutQualifiers(targetVersion);
1499	const char*				vtxIn		= usesInout ? "in" : "attribute";
1500	ostringstream			decl;
1501	ostringstream			setup;
1502	map<string, string>		params;
1503
1504	decl << vtxIn << " highp vec4 dEQP_Position;\n";
1505
1506	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1507	{
1508		const ShaderCase::Value&	val		= valueBlock.values[ndx];
1509		const char*					typeStr	= getDataTypeName(val.dataType);
1510
1511		if (val.storageType == ShaderCase::Value::STORAGE_INPUT)
1512		{
1513			if (getDataTypeScalarType(val.dataType) == TYPE_FLOAT)
1514			{
1515				decl << vtxIn << " " << typeStr << " " << val.valueName << ";\n";
1516			}
1517			else
1518			{
1519				DataType	floatType		= getDataTypeFloatScalars(val.dataType);
1520				const char*	floatTypeStr	= getDataTypeName(floatType);
1521
1522				decl << vtxIn << " " << floatTypeStr << " a_" << val.valueName << ";\n";
1523				setup << typeStr << " " << val.valueName << " = " << typeStr << "(a_" << val.valueName << ");\n";
1524			}
1525		}
1526		else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1527					val.valueName.find('.') == string::npos)
1528			decl << "uniform " << typeStr << " " << val.valueName << ";\n";
1529	}
1530
1531	params.insert(pair<string, string>("VERTEX_DECLARATIONS",		decl.str()));
1532	params.insert(pair<string, string>("VERTEX_SETUP",				setup.str()));
1533	params.insert(pair<string, string>("VERTEX_OUTPUT",				string("gl_Position = dEQP_Position;\n")));
1534	return params;
1535}
1536
1537static map<string, string> generateFragmentSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1538{
1539	const bool			usesInout		= usesShaderInoutQualifiers(targetVersion);
1540	const bool			customColorOut	= usesInout;
1541	const char*			fragColor		= customColorOut ? "dEQP_FragColor"	: "gl_FragColor";
1542	ostringstream		decl;
1543	ostringstream		output;
1544	map<string, string>	params;
1545
1546	genCompareFunctions(decl, valueBlock, false);
1547	genCompareOp(output, fragColor, valueBlock, "", DE_NULL);
1548
1549	if (customColorOut)
1550		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1551
1552	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1553	{
1554		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1555		const char*					valueName		= val.valueName.c_str();
1556		const char*					refTypeStr		= getDataTypeName(val.dataType);
1557
1558		if (val.storageType == ShaderCase::Value::STORAGE_OUTPUT)
1559		{
1560			decl << "uniform " << refTypeStr << " ref_" << valueName << ";\n";
1561			decl << refTypeStr << " " << valueName << ";\n";
1562		}
1563		else if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1564					val.valueName.find('.') == string::npos)
1565		{
1566			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1567		}
1568	}
1569
1570	params.insert(pair<string, string>("FRAGMENT_DECLARATIONS",		decl.str()));
1571	params.insert(pair<string, string>("FRAGMENT_OUTPUT",			output.str()));
1572	params.insert(pair<string, string>("FRAG_COLOR",				fragColor));
1573	return params;
1574}
1575
1576static map<string, string> generateGeometrySpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1577{
1578	ostringstream		decl;
1579	map<string, string>	params;
1580
1581	DE_UNREF(targetVersion);
1582
1583	decl << "layout (triangles) in;\n";
1584	decl << "layout (triangle_strip, max_vertices=3) out;\n";
1585	decl << "\n";
1586
1587	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1588	{
1589		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1590		const char*					valueName		= val.valueName.c_str();
1591		const char*					refTypeStr		= getDataTypeName(val.dataType);
1592
1593		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1594			val.valueName.find('.') == string::npos)
1595		{
1596			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1597		}
1598	}
1599
1600	params.insert(pair<string, string>("GEOMETRY_DECLARATIONS",		decl.str()));
1601	return params;
1602}
1603
1604static map<string, string> generateTessControlSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1605{
1606	ostringstream		decl;
1607	ostringstream		output;
1608	map<string, string>	params;
1609
1610	DE_UNREF(targetVersion);
1611
1612	decl << "layout (vertices=3) out;\n";
1613	decl << "\n";
1614
1615	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1616	{
1617		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1618		const char*					valueName		= val.valueName.c_str();
1619		const char*					refTypeStr		= getDataTypeName(val.dataType);
1620
1621		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1622			val.valueName.find('.') == string::npos)
1623		{
1624			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1625		}
1626	}
1627
1628	output <<	"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1629				"gl_TessLevelInner[0] = 2.0;\n"
1630				"gl_TessLevelInner[1] = 2.0;\n"
1631				"gl_TessLevelOuter[0] = 2.0;\n"
1632				"gl_TessLevelOuter[1] = 2.0;\n"
1633				"gl_TessLevelOuter[2] = 2.0;\n"
1634				"gl_TessLevelOuter[3] = 2.0;";
1635
1636	params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS",	decl.str()));
1637	params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT",		output.str()));
1638	return params;
1639}
1640
1641static map<string, string> generateTessEvalSpecialization (glu::GLSLVersion targetVersion, const ShaderCase::ValueBlock& valueBlock)
1642{
1643	ostringstream		decl;
1644	ostringstream		output;
1645	map<string, string>	params;
1646
1647	DE_UNREF(targetVersion);
1648
1649	decl << "layout (triangles) in;\n";
1650	decl << "\n";
1651
1652	for (int ndx = 0; ndx < (int)valueBlock.values.size(); ndx++)
1653	{
1654		const ShaderCase::Value&	val				= valueBlock.values[ndx];
1655		const char*					valueName		= val.valueName.c_str();
1656		const char*					refTypeStr		= getDataTypeName(val.dataType);
1657
1658		if (val.storageType == ShaderCase::Value::STORAGE_UNIFORM &&
1659			val.valueName.find('.') == string::npos)
1660		{
1661			decl << "uniform " << refTypeStr << " " << valueName << ";\n";
1662		}
1663	}
1664
1665	output <<	"gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n";
1666
1667	params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS",	decl.str()));
1668	params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT",		output.str()));
1669	return params;
1670}
1671
1672static void specializeShaders (glu::ProgramSources& dst, glu::ShaderType shaderType, const std::vector<std::string>& sources, const ShaderCase::ValueBlock& valueBlock, glu::GLSLVersion targetVersion, const std::vector<ShaderCase::CaseRequirement>& requirements, std::map<std::string, std::string> (*specializationGenerator)(glu::GLSLVersion, const ShaderCase::ValueBlock&))
1673{
1674	if (!sources.empty())
1675	{
1676		const std::map<std::string, std::string> specializationParams = specializationGenerator(targetVersion, valueBlock);
1677
1678		for (int ndx = 0; ndx < (int)sources.size(); ++ndx)
1679		{
1680			const StringTemplate	tmpl			(sources[ndx]);
1681			const std::string		baseGLSLCode	= tmpl.specialize(specializationParams);
1682			const std::string		glslSource		= injectExtensionRequirements(baseGLSLCode, shaderType, requirements);
1683
1684			dst << glu::ShaderSource(shaderType, glslSource);
1685		}
1686	}
1687}
1688
1689void ShaderCase::specializeVertexShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1690{
1691	specializeShaders(dst, glu::SHADERTYPE_VERTEX, sources, valueBlock, m_targetVersion, requirements, generateVertexSpecialization);
1692}
1693
1694void ShaderCase::specializeFragmentShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1695{
1696	specializeShaders(dst, glu::SHADERTYPE_FRAGMENT, sources, valueBlock, m_targetVersion, requirements, generateFragmentSpecialization);
1697}
1698
1699void ShaderCase::specializeGeometryShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1700{
1701	specializeShaders(dst, glu::SHADERTYPE_GEOMETRY, sources, valueBlock, m_targetVersion, requirements, generateGeometrySpecialization);
1702}
1703
1704void ShaderCase::specializeTessControlShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1705{
1706	specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_CONTROL, sources, valueBlock, m_targetVersion, requirements, generateTessControlSpecialization);
1707}
1708
1709void ShaderCase::specializeTessEvalShaders (glu::ProgramSources& dst, const std::vector<std::string>& sources, const ValueBlock& valueBlock, const std::vector<ShaderCase::CaseRequirement>& requirements) const
1710{
1711	specializeShaders(dst, glu::SHADERTYPE_TESSELLATION_EVALUATION, sources, valueBlock, m_targetVersion, requirements, generateTessEvalSpecialization);
1712}
1713
1714void ShaderCase::dumpValues (const ValueBlock& valueBlock, int arrayNdx)
1715{
1716	int numValues = (int)valueBlock.values.size();
1717	for (int valNdx = 0; valNdx < numValues; valNdx++)
1718	{
1719		const ShaderCase::Value&	val				= valueBlock.values[valNdx];
1720		const char*					valueName		= val.valueName.c_str();
1721		DataType					dataType		= val.dataType;
1722		int							scalarSize		= getDataTypeScalarSize(val.dataType);
1723		ostringstream				result;
1724
1725		result << "    ";
1726		if (val.storageType == Value::STORAGE_INPUT)
1727			result << "input ";
1728		else if (val.storageType == Value::STORAGE_UNIFORM)
1729			result << "uniform ";
1730		else if (val.storageType == Value::STORAGE_OUTPUT)
1731			result << "expected ";
1732
1733		result << getDataTypeName(dataType) << " " << valueName << ":";
1734
1735		if (isDataTypeScalar(dataType))
1736			result << " ";
1737		if (isDataTypeVector(dataType))
1738			result << " [ ";
1739		else if (isDataTypeMatrix(dataType))
1740			result << "\n";
1741
1742		if (isDataTypeScalarOrVector(dataType))
1743		{
1744			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1745			{
1746				int						elemNdx	= (val.arrayLength == 1) ? 0 : arrayNdx;
1747				const Value::Element&	e		= val.elements[elemNdx*scalarSize + scalarNdx];
1748				result << ((scalarNdx != 0) ? ", " : "");
1749
1750				if (isDataTypeFloatOrVec(dataType))
1751					result << e.float32;
1752				else if (isDataTypeIntOrIVec(dataType))
1753					result << e.int32;
1754				else if (isDataTypeUintOrUVec(dataType))
1755					result << (deUint32)e.int32;
1756				else if (isDataTypeBoolOrBVec(dataType))
1757					result << (e.bool32 ? "true" : "false");
1758			}
1759		}
1760		else if (isDataTypeMatrix(dataType))
1761		{
1762			int numRows = getDataTypeMatrixNumRows(dataType);
1763			int numCols = getDataTypeMatrixNumColumns(dataType);
1764			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1765			{
1766				result << "       [ ";
1767				for (int colNdx = 0; colNdx < numCols; colNdx++)
1768				{
1769					int		elemNdx = (val.arrayLength == 1) ? 0 : arrayNdx;
1770					float	v		= val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32;
1771					result << ((colNdx==0) ? "" : ", ") << v;
1772				}
1773				result << " ]\n";
1774			}
1775		}
1776
1777		if (isDataTypeScalar(dataType))
1778			result << "\n";
1779		else if (isDataTypeVector(dataType))
1780			result << " ]\n";
1781
1782		m_testCtx.getLog() << TestLog::Message << result.str() << TestLog::EndMessage;
1783	}
1784}
1785
1786} // sl
1787} // gls
1788} // deqp
1789