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