Home | History | Annotate | Download | only in glshared
      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 
     51 using namespace std;
     52 using namespace tcu;
     53 using namespace glu;
     54 
     55 namespace deqp
     56 {
     57 namespace gls
     58 {
     59 namespace sl
     60 {
     61 
     62 enum
     63 {
     64 	VIEWPORT_WIDTH		= 128,
     65 	VIEWPORT_HEIGHT		= 128
     66 };
     67 
     68 static 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 
     83 static inline bool supportsFragmentHighp (glu::GLSLVersion version)
     84 {
     85 	return version != glu::GLSL_VERSION_100_ES;
     86 }
     87 
     88 ShaderCase::ValueBlock::ValueBlock (void)
     89 	: arrayLength(0)
     90 {
     91 }
     92 
     93 ShaderCase::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 
    102 ShaderCase::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 
    113 ShaderCase::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 
    124 void 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 
    184 ShaderCase::ShaderCaseSpecification::ShaderCaseSpecification (void)
    185 	: expectResult	(EXPECT_LAST)
    186 	, targetVersion	(glu::GLSL_VERSION_LAST)
    187 	, caseType		(CASETYPE_COMPLETE)
    188 {
    189 }
    190 
    191 ShaderCase::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 
    202 ShaderCase::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 
    213 class BeforeDrawValidator : public glu::DrawUtilCallback
    214 {
    215 public:
    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 
    231 private:
    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 
    240 BeforeDrawValidator::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 
    249 void 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 
    312 const std::string& BeforeDrawValidator::getInfoLog (void) const
    313 {
    314 	return m_logMessage;
    315 }
    316 
    317 glw::GLint BeforeDrawValidator::getValidateStatus (void) const
    318 {
    319 	return m_validateStatus;
    320 }
    321 
    322 // ShaderCase.
    323 
    324 ShaderCase::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 
    367 ShaderCase::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 
    407 ShaderCase::~ShaderCase (void)
    408 {
    409 }
    410 
    411 void 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 
    490 static 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 
    552 bool 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 
    569 bool 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 
    606 bool 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 
   1035 TestCase::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 
   1047 static 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
   1056 static 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'.
   1092 string 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 
   1146 static 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 
   1206 static 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 
   1245 string 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.
   1299 string 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.
   1365 string 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 
   1427 static 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 
   1468 static 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 
   1507 static 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 
   1535 static 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 
   1572 static 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 
   1603 static 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 
   1620 void 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 
   1625 void 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 
   1630 void 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 
   1635 void 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 
   1640 void 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 
   1645 void 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