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 #include "tcuTextureUtil.hpp"
     29 #include "tcuSurface.hpp"
     30 
     31 #include "tcuStringTemplate.hpp"
     32 #include "gluShaderProgram.hpp"
     33 #include "gluPixelTransfer.hpp"
     34 #include "gluDrawUtil.hpp"
     35 #include "gluContextInfo.hpp"
     36 #include "gluStrUtil.hpp"
     37 
     38 #include "glwFunctions.hpp"
     39 #include "glwEnums.hpp"
     40 
     41 #include "deRandom.hpp"
     42 #include "deInt32.h"
     43 #include "deMath.h"
     44 #include "deString.h"
     45 #include "deStringUtil.hpp"
     46 #include "deSharedPtr.hpp"
     47 
     48 #include <map>
     49 #include <vector>
     50 #include <string>
     51 #include <sstream>
     52 
     53 namespace deqp
     54 {
     55 namespace gls
     56 {
     57 
     58 using namespace tcu;
     59 using namespace glu;
     60 using namespace glu::sl;
     61 
     62 using std::vector;
     63 using std::string;
     64 using std::ostringstream;
     65 using std::map;
     66 using std::pair;
     67 
     68 using de::SharedPtr;
     69 
     70 // OpenGL-specific specialization utils
     71 
     72 static vector<RequiredExtension> checkAndSpecializeExtensions (const vector<RequiredExtension>&	src,
     73 															   const ContextInfo&				ctxInfo)
     74 {
     75 	vector<RequiredExtension>	specialized;
     76 
     77 	for (size_t extNdx = 0; extNdx < src.size(); ++extNdx)
     78 	{
     79 		const RequiredExtension&	extension		= src[extNdx];
     80 		int							supportedAltNdx	= -1;
     81 
     82 		for (size_t alternativeNdx = 0; alternativeNdx < extension.alternatives.size(); ++alternativeNdx)
     83 		{
     84 			if (ctxInfo.isExtensionSupported(extension.alternatives[alternativeNdx].c_str()))
     85 			{
     86 				supportedAltNdx	= (int)alternativeNdx;
     87 				break;
     88 			}
     89 		}
     90 
     91 		if (supportedAltNdx >= 0)
     92 		{
     93 			specialized.push_back(RequiredExtension(extension.alternatives[supportedAltNdx], extension.effectiveStages));
     94 		}
     95 		else
     96 		{
     97 			// no extension(s). Make a nice output
     98 			std::ostringstream extensionList;
     99 
    100 			for (size_t ndx = 0; ndx < extension.alternatives.size(); ++ndx)
    101 			{
    102 				if (!extensionList.str().empty())
    103 					extensionList << ", ";
    104 				extensionList << extension.alternatives[ndx];
    105 			}
    106 
    107 			if (extension.alternatives.size() == 1)
    108 				throw tcu::NotSupportedError("Test requires extension " + extensionList.str());
    109 			else
    110 				throw tcu::NotSupportedError("Test requires any extension of " + extensionList.str());
    111 		}
    112 	}
    113 
    114 	return specialized;
    115 }
    116 
    117 static void checkImplementationLimits (const vector<RequiredCapability>&	requiredCaps,
    118 									   const ContextInfo&					ctxInfo)
    119 {
    120 	for (size_t capNdx = 0; capNdx < requiredCaps.size(); ++capNdx)
    121 	{
    122 		const deUint32	pname			= requiredCaps[capNdx].enumName;
    123 		const int		requiredValue	= requiredCaps[capNdx].referenceValue;
    124 		const int		supportedValue	= ctxInfo.getInt((int)pname);
    125 
    126 		if (supportedValue <= requiredValue)
    127 			throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " (" + de::toString(supportedValue) + ") >= " + de::toString(requiredValue));
    128 	}
    129 }
    130 
    131 // Shader source specialization
    132 
    133 // This functions builds a matching vertex shader for a 'both' case, when
    134 // the fragment shader is being tested.
    135 // We need to build attributes and varyings for each 'input'.
    136 static string genVertexShader (const ShaderCaseSpecification& spec)
    137 {
    138 	ostringstream		res;
    139 	const bool			usesInout	= glslVersionUsesInOutQualifiers(spec.targetVersion);
    140 	const char* const	vtxIn		= usesInout ? "in"	: "attribute";
    141 	const char* const	vtxOut		= usesInout ? "out"	: "varying";
    142 
    143 	res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
    144 
    145 	// Declarations (position + attribute/varying for each input).
    146 	res << "precision highp float;\n";
    147 	res << "precision highp int;\n";
    148 	res << "\n";
    149 	res << vtxIn << " highp vec4 dEQP_Position;\n";
    150 
    151 	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
    152 	{
    153 		const Value&		val			= spec.values.inputs[ndx];
    154 		const DataType		basicType	= val.type.getBasicType();
    155 		const DataType		floatType	= getDataTypeFloatScalars(basicType);
    156 		const char* const	typeStr		= getDataTypeName(floatType);
    157 
    158 		res << vtxIn << " " << typeStr << " a_" << val.name << ";\n";
    159 
    160 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    161 			res << vtxOut << " " << typeStr << " " << val.name << ";\n";
    162 		else
    163 			res << vtxOut << " " << typeStr << " v_" << val.name << ";\n";
    164 	}
    165 	res << "\n";
    166 
    167 	// Main function.
    168 	// - gl_Position = dEQP_Position;
    169 	// - for each input: write attribute directly to varying
    170 	res << "void main()\n";
    171 	res << "{\n";
    172 	res << "	gl_Position = dEQP_Position;\n";
    173 	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
    174 	{
    175 		const Value&	val		= spec.values.inputs[ndx];
    176 		const string&	name	= val.name;
    177 
    178 		if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
    179 			res << "	" << name << " = a_" << name << ";\n";
    180 		else
    181 			res << "	v_" << name << " = a_" << name << ";\n";
    182 	}
    183 
    184 	res << "}\n";
    185 	return res.str();
    186 }
    187 
    188 static void genCompareOp (ostringstream& output, const char* dstVec4Var, const ValueBlock& valueBlock, const char* nonFloatNamePrefix, const char* checkVarName)
    189 {
    190 	bool isFirstOutput = true;
    191 
    192 	for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++)
    193 	{
    194 		const Value&	val		= valueBlock.outputs[ndx];
    195 
    196 		// Check if we're only interested in one variable (then skip if not the right one).
    197 		if (checkVarName && val.name != checkVarName)
    198 			continue;
    199 
    200 		// Prefix.
    201 		if (isFirstOutput)
    202 		{
    203 			output << "bool RES = ";
    204 			isFirstOutput = false;
    205 		}
    206 		else
    207 			output << "RES = RES && ";
    208 
    209 		// Generate actual comparison.
    210 		if (getDataTypeScalarType(val.type.getBasicType()) == TYPE_FLOAT)
    211 			output << "isOk(" << val.name << ", ref_" << val.name << ", 0.05);\n";
    212 		else
    213 			output << "isOk(" << nonFloatNamePrefix << val.name << ", ref_" << val.name << ");\n";
    214 	}
    215 
    216 	if (isFirstOutput)
    217 		output << dstVec4Var << " = vec4(1.0);\n";	// \todo [petri] Should we give warning if not expect-failure case?
    218 	else
    219 		output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
    220 }
    221 
    222 static inline bool supportsFragmentHighp (glu::GLSLVersion version)
    223 {
    224 	return version != glu::GLSL_VERSION_100_ES;
    225 }
    226 
    227 static string genFragmentShader (const ShaderCaseSpecification& spec)
    228 {
    229 	ostringstream		shader;
    230 	const bool			usesInout		= glslVersionUsesInOutQualifiers(spec.targetVersion);
    231 	const bool			customColorOut	= usesInout;
    232 	const char*	const	fragIn			= usesInout ? "in" : "varying";
    233 	const char*	const	prec			= supportsFragmentHighp(spec.targetVersion) ? "highp" : "mediump";
    234 
    235 	shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
    236 
    237 	shader << "precision " << prec << " float;\n";
    238 	shader << "precision " << prec << " int;\n";
    239 	shader << "\n";
    240 
    241 	if (customColorOut)
    242 	{
    243 		shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
    244 		shader << "\n";
    245 	}
    246 
    247 	genCompareFunctions(shader, spec.values, true);
    248 	shader << "\n";
    249 
    250 	// Declarations (varying, reference for each output).
    251 	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
    252 	{
    253 		const Value&		val				= spec.values.outputs[ndx];
    254 		const DataType		basicType		= val.type.getBasicType();
    255 		const DataType		floatType		= getDataTypeFloatScalars(basicType);
    256 		const char* const	floatTypeStr	= getDataTypeName(floatType);
    257 		const char* const	refTypeStr		= getDataTypeName(basicType);
    258 
    259 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    260 			shader << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
    261 		else
    262 			shader << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
    263 
    264 		shader << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
    265 	}
    266 
    267 	shader << "\n";
    268 	shader << "void main()\n";
    269 	shader << "{\n";
    270 
    271 	shader << "	";
    272 	genCompareOp(shader, customColorOut ? "dEQP_FragColor" : "gl_FragColor", spec.values, "v_", DE_NULL);
    273 
    274 	shader << "}\n";
    275 	return shader.str();
    276 }
    277 
    278 // Specialize a shader for the vertex shader test case.
    279 static string specializeVertexShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
    280 {
    281 	ostringstream		decl;
    282 	ostringstream		setup;
    283 	ostringstream		output;
    284 	const bool			usesInout	= glslVersionUsesInOutQualifiers(spec.targetVersion);
    285 	const char* const	vtxIn		= usesInout ? "in"	: "attribute";
    286 	const char* const	vtxOut		= usesInout ? "out"	: "varying";
    287 
    288 	// generated from "both" case
    289 	DE_ASSERT(spec.caseType == CASETYPE_VERTEX_ONLY);
    290 
    291 	// Output (write out position).
    292 	output << "gl_Position = dEQP_Position;\n";
    293 
    294 	// Declarations (position + attribute for each input, varying for each output).
    295 	decl << vtxIn << " highp vec4 dEQP_Position;\n";
    296 
    297 	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
    298 	{
    299 		const Value&		val				= spec.values.inputs[ndx];
    300 		const DataType		basicType		= val.type.getBasicType();
    301 		const DataType		floatType		= getDataTypeFloatScalars(basicType);
    302 		const char* const	floatTypeStr	= getDataTypeName(floatType);
    303 		const char* const	refTypeStr		= getDataTypeName(basicType);
    304 
    305 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    306 		{
    307 			decl << vtxIn << " " << floatTypeStr << " " << val.name << ";\n";
    308 		}
    309 		else
    310 		{
    311 			decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
    312 			setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(a_" << val.name << ");\n";
    313 		}
    314 	}
    315 
    316 	// \todo [2015-07-24 pyry] Why are uniforms missing?
    317 
    318 	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
    319 	{
    320 		const Value&		val				= spec.values.outputs[ndx];
    321 		const DataType		basicType		= val.type.getBasicType();
    322 		const DataType		floatType		= getDataTypeFloatScalars(basicType);
    323 		const char* const	floatTypeStr	= getDataTypeName(floatType);
    324 		const char* const	refTypeStr		= getDataTypeName(basicType);
    325 
    326 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    327 			decl << vtxOut << " " << floatTypeStr << " " << val.name << ";\n";
    328 		else
    329 		{
    330 			decl << vtxOut << " " << floatTypeStr << " v_" << val.name << ";\n";
    331 			decl << refTypeStr << " " << val.name << ";\n";
    332 
    333 			output << "v_" << val.name << " = " << floatTypeStr << "(" << val.name << ");\n";
    334 		}
    335 	}
    336 
    337 	// Shader specialization.
    338 	map<string, string> params;
    339 	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
    340 	params.insert(pair<string, string>("SETUP", setup.str()));
    341 	params.insert(pair<string, string>("OUTPUT", output.str()));
    342 	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
    343 
    344 	StringTemplate	tmpl	(src);
    345 	const string	baseSrc	= tmpl.specialize(params);
    346 	const string	withExt	= injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_VERTEX);
    347 
    348 	return withExt;
    349 }
    350 
    351 // Specialize a shader for the fragment shader test case.
    352 static string specializeFragmentShader (const ShaderCaseSpecification& spec, const std::string& src, const vector<RequiredExtension>& extensions)
    353 {
    354 	ostringstream		decl;
    355 	ostringstream		setup;
    356 	ostringstream		output;
    357 
    358 	const bool			usesInout		= glslVersionUsesInOutQualifiers(spec.targetVersion);
    359 	const bool			customColorOut	= usesInout;
    360 	const char* const	fragIn			= usesInout			? "in"				: "varying";
    361 	const char* const	fragColor		= customColorOut	? "dEQP_FragColor"	: "gl_FragColor";
    362 
    363 	// generated from "both" case
    364 	DE_ASSERT(spec.caseType == CASETYPE_FRAGMENT_ONLY);
    365 
    366 	genCompareFunctions(decl, spec.values, false);
    367 	genCompareOp(output, fragColor, spec.values, "", DE_NULL);
    368 
    369 	if (customColorOut)
    370 		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
    371 
    372 	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
    373 	{
    374 		const Value&		val				= spec.values.inputs[ndx];
    375 		const DataType		basicType		= val.type.getBasicType();
    376 		const DataType		floatType		= getDataTypeFloatScalars(basicType);
    377 		const char* const	floatTypeStr	= getDataTypeName(floatType);
    378 		const char* const	refTypeStr		= getDataTypeName(basicType);
    379 
    380 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    381 			decl << fragIn << " " << floatTypeStr << " " << val.name << ";\n";
    382 		else
    383 		{
    384 			decl << fragIn << " " << floatTypeStr << " v_" << val.name << ";\n";
    385 			std::string offset = isDataTypeIntOrIVec(basicType) ? " * 1.0025" : ""; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
    386 			setup << refTypeStr << " " << val.name << " = " << refTypeStr << "(v_" << val.name << offset << ");\n";
    387 		}
    388 	}
    389 
    390 	// \todo [2015-07-24 pyry] Why are uniforms missing?
    391 
    392 	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
    393 	{
    394 		const Value&		val				= spec.values.outputs[ndx];
    395 		const DataType		basicType		= val.type.getBasicType();
    396 		const char* const	refTypeStr		= getDataTypeName(basicType);
    397 
    398 		decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
    399 		decl << refTypeStr << " " << val.name << ";\n";
    400 	}
    401 
    402 	/* \todo [2010-04-01 petri] Check all outputs. */
    403 
    404 	// Shader specialization.
    405 	map<string, string> params;
    406 	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
    407 	params.insert(pair<string, string>("SETUP", setup.str()));
    408 	params.insert(pair<string, string>("OUTPUT", output.str()));
    409 	params.insert(pair<string, string>("POSITION_FRAG_COLOR", fragColor));
    410 
    411 	StringTemplate	tmpl	(src);
    412 	const string	baseSrc	= tmpl.specialize(params);
    413 	const string	withExt	= injectExtensionRequirements(baseSrc, extensions, SHADERTYPE_FRAGMENT);
    414 
    415 	return withExt;
    416 }
    417 
    418 static void generateUniformDeclarations (std::ostream& dst, const ValueBlock& valueBlock)
    419 {
    420 	for (size_t ndx = 0; ndx < valueBlock.uniforms.size(); ndx++)
    421 	{
    422 		const Value&		val		= valueBlock.uniforms[ndx];
    423 		const char* const	typeStr	= getDataTypeName(val.type.getBasicType());
    424 
    425 		if (val.name.find('.') == string::npos)
    426 			dst << "uniform " << typeStr << " " << val.name << ";\n";
    427 	}
    428 }
    429 
    430 static map<string, string> generateVertexSpecialization (const ProgramSpecializationParams& specParams)
    431 {
    432 	const bool				usesInout	= glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
    433 	const char*				vtxIn		= usesInout ? "in" : "attribute";
    434 	ostringstream			decl;
    435 	ostringstream			setup;
    436 	map<string, string>		params;
    437 
    438 	decl << vtxIn << " highp vec4 dEQP_Position;\n";
    439 
    440 	for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++)
    441 	{
    442 		const Value&		val			= specParams.caseSpec.values.inputs[ndx];
    443 		const DataType		basicType	= val.type.getBasicType();
    444 		const char* const	typeStr		= getDataTypeName(val.type.getBasicType());
    445 
    446 		if (getDataTypeScalarType(basicType) == TYPE_FLOAT)
    447 		{
    448 			decl << vtxIn << " " << typeStr << " " << val.name << ";\n";
    449 		}
    450 		else
    451 		{
    452 			const DataType		floatType		= getDataTypeFloatScalars(basicType);
    453 			const char* const	floatTypeStr	= getDataTypeName(floatType);
    454 
    455 			decl << vtxIn << " " << floatTypeStr << " a_" << val.name << ";\n";
    456 			setup << typeStr << " " << val.name << " = " << typeStr << "(a_" << val.name << ");\n";
    457 		}
    458 	}
    459 
    460 	generateUniformDeclarations(decl, specParams.caseSpec.values);
    461 
    462 	params.insert(pair<string, string>("VERTEX_DECLARATIONS",	decl.str()));
    463 	params.insert(pair<string, string>("VERTEX_SETUP",			setup.str()));
    464 	params.insert(pair<string, string>("VERTEX_OUTPUT",			string("gl_Position = dEQP_Position;\n")));
    465 
    466 	return params;
    467 }
    468 
    469 static map<string, string> generateFragmentSpecialization (const ProgramSpecializationParams& specParams)
    470 {
    471 	const bool			usesInout		= glslVersionUsesInOutQualifiers(specParams.caseSpec.targetVersion);
    472 	const bool			customColorOut	= usesInout;
    473 	const char* const	fragColor		= customColorOut ? "dEQP_FragColor"	: "gl_FragColor";
    474 	ostringstream		decl;
    475 	ostringstream		output;
    476 	map<string, string>	params;
    477 
    478 	genCompareFunctions(decl, specParams.caseSpec.values, false);
    479 	genCompareOp(output, fragColor, specParams.caseSpec.values, "", DE_NULL);
    480 
    481 	if (customColorOut)
    482 		decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
    483 
    484 	for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++)
    485 	{
    486 		const Value&		val			= specParams.caseSpec.values.outputs[ndx];
    487 		const char*	const	refTypeStr	= getDataTypeName(val.type.getBasicType());
    488 
    489 		decl << "uniform " << refTypeStr << " ref_" << val.name << ";\n";
    490 		decl << refTypeStr << " " << val.name << ";\n";
    491 	}
    492 
    493 	generateUniformDeclarations(decl, specParams.caseSpec.values);
    494 
    495 	params.insert(pair<string, string>("FRAGMENT_DECLARATIONS",	decl.str()));
    496 	params.insert(pair<string, string>("FRAGMENT_OUTPUT",		output.str()));
    497 	params.insert(pair<string, string>("FRAG_COLOR",			fragColor));
    498 
    499 	return params;
    500 }
    501 
    502 static map<string, string> generateGeometrySpecialization (const ProgramSpecializationParams& specParams)
    503 {
    504 	ostringstream		decl;
    505 	map<string, string>	params;
    506 
    507 	decl << "layout (triangles) in;\n";
    508 	decl << "layout (triangle_strip, max_vertices=3) out;\n";
    509 	decl << "\n";
    510 
    511 	generateUniformDeclarations(decl, specParams.caseSpec.values);
    512 
    513 	params.insert(pair<string, string>("GEOMETRY_DECLARATIONS",		decl.str()));
    514 
    515 	return params;
    516 }
    517 
    518 static map<string, string> generateTessControlSpecialization (const ProgramSpecializationParams& specParams)
    519 {
    520 	ostringstream		decl;
    521 	ostringstream		output;
    522 	map<string, string>	params;
    523 
    524 	decl << "layout (vertices=3) out;\n";
    525 	decl << "\n";
    526 
    527 	generateUniformDeclarations(decl, specParams.caseSpec.values);
    528 
    529 	output <<	"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    530 				"gl_TessLevelInner[0] = 2.0;\n"
    531 				"gl_TessLevelInner[1] = 2.0;\n"
    532 				"gl_TessLevelOuter[0] = 2.0;\n"
    533 				"gl_TessLevelOuter[1] = 2.0;\n"
    534 				"gl_TessLevelOuter[2] = 2.0;\n"
    535 				"gl_TessLevelOuter[3] = 2.0;";
    536 
    537 	params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS",	decl.str()));
    538 	params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT",		output.str()));
    539 	params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",				de::toString(specParams.maxPatchVertices)));
    540 
    541 	return params;
    542 }
    543 
    544 static map<string, string> generateTessEvalSpecialization (const ProgramSpecializationParams& specParams)
    545 {
    546 	ostringstream		decl;
    547 	ostringstream		output;
    548 	map<string, string>	params;
    549 
    550 	decl << "layout (triangles) in;\n";
    551 	decl << "\n";
    552 
    553 	generateUniformDeclarations(decl, specParams.caseSpec.values);
    554 
    555 	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";
    556 
    557 	params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS",	decl.str()));
    558 	params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT",		output.str()));
    559 	params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",					de::toString(specParams.maxPatchVertices)));
    560 
    561 	return params;
    562 }
    563 
    564 static void specializeShaderSources (ProgramSources&					dst,
    565 									 const ProgramSources&				src,
    566 									 const ProgramSpecializationParams&	specParams,
    567 									 glu::ShaderType					shaderType,
    568 									 map<string, string>				(*specializationGenerator) (const ProgramSpecializationParams& specParams))
    569 {
    570 	if (!src.sources[shaderType].empty())
    571 	{
    572 		const map<string, string>	tmplParams	= specializationGenerator(specParams);
    573 
    574 		for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx)
    575 		{
    576 			const StringTemplate	tmpl			(src.sources[shaderType][ndx]);
    577 			const std::string		baseGLSLCode	= tmpl.specialize(tmplParams);
    578 			const std::string		sourceWithExts	= injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType);
    579 
    580 			dst << glu::ShaderSource(shaderType, sourceWithExts);
    581 		}
    582 	}
    583 }
    584 
    585 static void specializeProgramSources (glu::ProgramSources&					dst,
    586 									  const glu::ProgramSources&			src,
    587 									  const ProgramSpecializationParams&	specParams)
    588 {
    589 	specializeShaderSources(dst, src, specParams, SHADERTYPE_VERTEX,					generateVertexSpecialization);
    590 	specializeShaderSources(dst, src, specParams, SHADERTYPE_FRAGMENT,					generateFragmentSpecialization);
    591 	specializeShaderSources(dst, src, specParams, SHADERTYPE_GEOMETRY,					generateGeometrySpecialization);
    592 	specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_CONTROL,		generateTessControlSpecialization);
    593 	specializeShaderSources(dst, src, specParams, SHADERTYPE_TESSELLATION_EVALUATION,	generateTessEvalSpecialization);
    594 
    595 	dst << ProgramSeparable(src.separable);
    596 }
    597 
    598 enum
    599 {
    600 	VIEWPORT_WIDTH		= 128,
    601 	VIEWPORT_HEIGHT		= 128
    602 };
    603 
    604 class BeforeDrawValidator : public glu::DrawUtilCallback
    605 {
    606 public:
    607 	enum TargetType
    608 	{
    609 		TARGETTYPE_PROGRAM = 0,
    610 		TARGETTYPE_PIPELINE,
    611 
    612 		TARGETTYPE_LAST
    613 	};
    614 
    615 							BeforeDrawValidator	(const glw::Functions& gl, glw::GLuint target, TargetType targetType);
    616 
    617 	void					beforeDrawCall		(void);
    618 
    619 	const std::string&		getInfoLog			(void) const;
    620 	glw::GLint				getValidateStatus	(void) const;
    621 
    622 private:
    623 	const glw::Functions&	m_gl;
    624 	const glw::GLuint		m_target;
    625 	const TargetType		m_targetType;
    626 
    627 	glw::GLint				m_validateStatus;
    628 	std::string				m_logMessage;
    629 };
    630 
    631 BeforeDrawValidator::BeforeDrawValidator (const glw::Functions& gl, glw::GLuint target, TargetType targetType)
    632 	: m_gl				(gl)
    633 	, m_target			(target)
    634 	, m_targetType		(targetType)
    635 	, m_validateStatus	(-1)
    636 {
    637 	DE_ASSERT(targetType < TARGETTYPE_LAST);
    638 }
    639 
    640 void BeforeDrawValidator::beforeDrawCall (void)
    641 {
    642 	glw::GLint					bytesWritten	= 0;
    643 	glw::GLint					infoLogLength;
    644 	std::vector<glw::GLchar>	logBuffer;
    645 	int							stringLength;
    646 
    647 	// validate
    648 	if (m_targetType == TARGETTYPE_PROGRAM)
    649 		m_gl.validateProgram(m_target);
    650 	else if (m_targetType == TARGETTYPE_PIPELINE)
    651 		m_gl.validateProgramPipeline(m_target);
    652 	else
    653 		DE_ASSERT(false);
    654 
    655 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "validate");
    656 
    657 	// check status
    658 	m_validateStatus = -1;
    659 
    660 	if (m_targetType == TARGETTYPE_PROGRAM)
    661 		m_gl.getProgramiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
    662 	else if (m_targetType == TARGETTYPE_PIPELINE)
    663 		m_gl.getProgramPipelineiv(m_target, GL_VALIDATE_STATUS, &m_validateStatus);
    664 	else
    665 		DE_ASSERT(false);
    666 
    667 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get validate status");
    668 	TCU_CHECK(m_validateStatus == GL_TRUE || m_validateStatus == GL_FALSE);
    669 
    670 	// read log
    671 
    672 	infoLogLength = 0;
    673 
    674 	if (m_targetType == TARGETTYPE_PROGRAM)
    675 		m_gl.getProgramiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
    676 	else if (m_targetType == TARGETTYPE_PIPELINE)
    677 		m_gl.getProgramPipelineiv(m_target, GL_INFO_LOG_LENGTH, &infoLogLength);
    678 	else
    679 		DE_ASSERT(false);
    680 
    681 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "get info log length");
    682 
    683 	if (infoLogLength <= 0)
    684 	{
    685 		m_logMessage.clear();
    686 		return;
    687 	}
    688 
    689 	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
    690 
    691 	if (m_targetType == TARGETTYPE_PROGRAM)
    692 		m_gl.getProgramInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
    693 	else if (m_targetType == TARGETTYPE_PIPELINE)
    694 		m_gl.getProgramPipelineInfoLog(m_target, infoLogLength + 1, &bytesWritten, &logBuffer[0]);
    695 	else
    696 		DE_ASSERT(false);
    697 
    698 	// just ignore bytesWritten to be safe, find the null terminator
    699 	stringLength = (int)(std::find(logBuffer.begin(), logBuffer.end(), '0') - logBuffer.begin());
    700 	m_logMessage.assign(&logBuffer[0], stringLength);
    701 }
    702 
    703 const std::string& BeforeDrawValidator::getInfoLog (void) const
    704 {
    705 	return m_logMessage;
    706 }
    707 
    708 glw::GLint BeforeDrawValidator::getValidateStatus (void) const
    709 {
    710 	return m_validateStatus;
    711 }
    712 
    713 // ShaderCase.
    714 
    715 ShaderLibraryCase::ShaderLibraryCase (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* name, const char* description, const ShaderCaseSpecification& specification)
    716 	: tcu::TestCase	(testCtx, name, description)
    717 	, m_renderCtx	(renderCtx)
    718 	, m_contextInfo	(contextInfo)
    719 	, m_spec		(specification)
    720 {
    721 }
    722 
    723 ShaderLibraryCase::~ShaderLibraryCase (void)
    724 {
    725 }
    726 
    727 void ShaderLibraryCase::init (void)
    728 {
    729 	DE_ASSERT(isValid(m_spec));
    730 
    731 	checkImplementationLimits(m_spec.requiredCaps, m_contextInfo);
    732 
    733 	// log the expected result
    734 	switch (m_spec.expectResult)
    735 	{
    736 		case EXPECT_PASS:
    737 			// Don't write anything
    738 			break;
    739 
    740 		case EXPECT_COMPILE_FAIL:
    741 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation to fail." << tcu::TestLog::EndMessage;
    742 			break;
    743 
    744 		case EXPECT_LINK_FAIL:
    745 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program linking to fail." << tcu::TestLog::EndMessage;
    746 			break;
    747 
    748 		case EXPECT_COMPILE_LINK_FAIL:
    749 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting either shader compilation or program linking to fail." << tcu::TestLog::EndMessage;
    750 			break;
    751 
    752 		case EXPECT_VALIDATION_FAIL:
    753 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting program validation to fail." << tcu::TestLog::EndMessage;
    754 			break;
    755 
    756 		case EXPECT_BUILD_SUCCESSFUL:
    757 			m_testCtx.getLog() << tcu::TestLog::Message << "Expecting shader compilation and program linking to succeed. Resulting program will not be executed." << tcu::TestLog::EndMessage;
    758 			break;
    759 
    760 		default:
    761 			DE_ASSERT(false);
    762 			break;
    763 	}
    764 }
    765 
    766 static void setUniformValue (const glw::Functions& gl, const std::vector<deUint32>& pipelinePrograms, const std::string& name, const Value& val, int arrayNdx, tcu::TestLog& log)
    767 {
    768 	bool foundAnyMatch = false;
    769 
    770 	for (int programNdx = 0; programNdx < (int)pipelinePrograms.size(); ++programNdx)
    771 	{
    772 		const DataType	dataType	= val.type.getBasicType();
    773 		const int		scalarSize	= getDataTypeScalarSize(dataType);
    774 		const int		loc			= gl.getUniformLocation(pipelinePrograms[programNdx], name.c_str());
    775 		const int		elemNdx		= arrayNdx * scalarSize;
    776 
    777 		DE_ASSERT(elemNdx+scalarSize <= (int)val.elements.size());
    778 
    779 		if (loc == -1)
    780 			continue;
    781 
    782 		foundAnyMatch = true;
    783 
    784 		DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLfloat));
    785 		DE_STATIC_ASSERT(sizeof(Value::Element) == sizeof(glw::GLint));
    786 
    787 		gl.useProgram(pipelinePrograms[programNdx]);
    788 
    789 		switch (dataType)
    790 		{
    791 			case TYPE_FLOAT:		gl.uniform1fv(loc, 1, &val.elements[elemNdx].float32);						break;
    792 			case TYPE_FLOAT_VEC2:	gl.uniform2fv(loc, 1, &val.elements[elemNdx].float32);						break;
    793 			case TYPE_FLOAT_VEC3:	gl.uniform3fv(loc, 1, &val.elements[elemNdx].float32);						break;
    794 			case TYPE_FLOAT_VEC4:	gl.uniform4fv(loc, 1, &val.elements[elemNdx].float32);						break;
    795 			case TYPE_FLOAT_MAT2:	gl.uniformMatrix2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
    796 			case TYPE_FLOAT_MAT3:	gl.uniformMatrix3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
    797 			case TYPE_FLOAT_MAT4:	gl.uniformMatrix4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);		break;
    798 			case TYPE_INT:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
    799 			case TYPE_INT_VEC2:		gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
    800 			case TYPE_INT_VEC3:		gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
    801 			case TYPE_INT_VEC4:		gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
    802 			case TYPE_BOOL:			gl.uniform1iv(loc, 1, &val.elements[elemNdx].int32);						break;
    803 			case TYPE_BOOL_VEC2:	gl.uniform2iv(loc, 1, &val.elements[elemNdx].int32);						break;
    804 			case TYPE_BOOL_VEC3:	gl.uniform3iv(loc, 1, &val.elements[elemNdx].int32);						break;
    805 			case TYPE_BOOL_VEC4:	gl.uniform4iv(loc, 1, &val.elements[elemNdx].int32);						break;
    806 			case TYPE_UINT:			gl.uniform1uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
    807 			case TYPE_UINT_VEC2:	gl.uniform2uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
    808 			case TYPE_UINT_VEC3:	gl.uniform3uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
    809 			case TYPE_UINT_VEC4:	gl.uniform4uiv(loc, 1, (const deUint32*)&val.elements[elemNdx].int32);		break;
    810 			case TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    811 			case TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    812 			case TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    813 			case TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    814 			case TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    815 			case TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(loc, 1, GL_FALSE, &val.elements[elemNdx].float32);	break;
    816 
    817 			case TYPE_SAMPLER_2D:
    818 			case TYPE_SAMPLER_CUBE:
    819 				DE_FATAL("implement!");
    820 				break;
    821 
    822 			default:
    823 				DE_ASSERT(false);
    824 		}
    825 	}
    826 
    827 	if (!foundAnyMatch)
    828 		log << tcu::TestLog::Message << "WARNING // Uniform \"" << name << "\" location is not valid, location = -1. Cannot set value to the uniform." << tcu::TestLog::EndMessage;
    829 }
    830 
    831 static bool isTessellationPresent (const ShaderCaseSpecification& spec)
    832 {
    833 	if (spec.programs[0].sources.separable)
    834 	{
    835 		const deUint32 tessellationBits =	(1 << glu::SHADERTYPE_TESSELLATION_CONTROL)		|
    836 											(1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
    837 
    838 		for (int programNdx = 0; programNdx < (int)spec.programs.size(); ++programNdx)
    839 			if (spec.programs[programNdx].activeStages & tessellationBits)
    840 				return true;
    841 		return false;
    842 	}
    843 	else
    844 		return !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty() ||
    845 			   !spec.programs[0].sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].empty();
    846 }
    847 
    848 static bool isTessellationSupported (const glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo)
    849 {
    850 	if (renderCtx.getType().getProfile() == PROFILE_ES)
    851 	{
    852 		const int	majorVer	= renderCtx.getType().getMajorVersion();
    853 		const int	minorVer	= renderCtx.getType().getMinorVersion();
    854 
    855 		return (majorVer > 3) || (majorVer == 3 && minorVer >= 2) ||
    856 			   ctxInfo.isExtensionSupported("GL_EXT_tessellation_shader");
    857 	}
    858 	else
    859 		return false;
    860 }
    861 
    862 static bool checkPixels (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& surface)
    863 {
    864 	bool	allWhite		= true;
    865 	bool	allBlack		= true;
    866 	bool	anyUnexpected	= false;
    867 
    868 	for (int y = 0; y < surface.getHeight(); y++)
    869 	{
    870 		for (int x = 0; x < surface.getWidth(); x++)
    871 		{
    872 			const tcu::IVec4	pixel		 = surface.getPixelInt(x, y);
    873 			// Note: we really do not want to involve alpha in the check comparison
    874 			// \todo [2010-09-22 kalle] Do we know that alpha would be one? If yes, could use color constants white and black.
    875 			const bool			isWhite		 = (pixel[0] == 255) && (pixel[1] == 255) && (pixel[2] == 255);
    876 			const bool			isBlack		 = (pixel[0] ==   0) && (pixel[1] ==   0) && (pixel[2] ==   0);
    877 
    878 			allWhite		= allWhite && isWhite;
    879 			allBlack		= allBlack && isBlack;
    880 			anyUnexpected	= anyUnexpected || (!isWhite && !isBlack);
    881 		}
    882 	}
    883 
    884 	if (!allWhite)
    885 	{
    886 		if (anyUnexpected)
    887 			log << TestLog::Message << "WARNING: expecting all rendered pixels to be white or black, but got other colors as well!" << TestLog::EndMessage;
    888 		else if (!allBlack)
    889 			log << TestLog::Message << "WARNING: got inconsistent results over the image, when all pixels should be the same color!" << TestLog::EndMessage;
    890 
    891 		return false;
    892 	}
    893 
    894 	return true;
    895 }
    896 
    897 bool ShaderLibraryCase::execute (void)
    898 {
    899 	const float							quadSize				= 1.0f;
    900 	static const float					s_positions[4*4]		=
    901 	{
    902 		-quadSize, -quadSize, 0.0f, 1.0f,
    903 		-quadSize, +quadSize, 0.0f, 1.0f,
    904 		+quadSize, -quadSize, 0.0f, 1.0f,
    905 		+quadSize, +quadSize, 0.0f, 1.0f
    906 	};
    907 
    908 	static const deUint16				s_indices[2*3]			=
    909 	{
    910 		0, 1, 2,
    911 		1, 3, 2
    912 	};
    913 
    914 	TestLog&							log						= m_testCtx.getLog();
    915 	const glw::Functions&				gl						= m_renderCtx.getFunctions();
    916 
    917 	// Compute viewport.
    918 	const tcu::RenderTarget&			renderTarget			= m_renderCtx.getRenderTarget();
    919 	de::Random							rnd						(deStringHash(getName()));
    920 	const int							width					= deMin32(renderTarget.getWidth(),	VIEWPORT_WIDTH);
    921 	const int							height					= deMin32(renderTarget.getHeight(),	VIEWPORT_HEIGHT);
    922 	const int							viewportX				= rnd.getInt(0, renderTarget.getWidth()  - width);
    923 	const int							viewportY				= rnd.getInt(0, renderTarget.getHeight() - height);
    924 	const int							numVerticesPerDraw		= 4;
    925 	const bool							tessellationPresent		= isTessellationPresent(m_spec);
    926 	const bool							separablePrograms		= m_spec.programs[0].sources.separable;
    927 
    928 	bool								allCompilesOk			= true;
    929 	bool								allLinksOk				= true;
    930 	const char*							failReason				= DE_NULL;
    931 
    932 	vector<ProgramSources>				specializedSources		(m_spec.programs.size());
    933 
    934 	deUint32							vertexProgramID			= -1;
    935 	vector<deUint32>					pipelineProgramIDs;
    936 	vector<SharedPtr<ShaderProgram> >	programs;
    937 	SharedPtr<ProgramPipeline>			programPipeline;
    938 
    939 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): start");
    940 
    941 	// Specialize shaders
    942 	if (m_spec.caseType == CASETYPE_VERTEX_ONLY)
    943 	{
    944 		const vector<RequiredExtension>	reqExt	= checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
    945 
    946 		DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX].size() == 1);
    947 		specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_VERTEX][0], reqExt))
    948 							  << glu::FragmentSource(genFragmentShader(m_spec));
    949 	}
    950 	else if (m_spec.caseType == CASETYPE_FRAGMENT_ONLY)
    951 	{
    952 		const vector<RequiredExtension>	reqExt	= checkAndSpecializeExtensions(m_spec.programs[0].requiredExtensions, m_contextInfo);
    953 
    954 		DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].size() == 1);
    955 		specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
    956 							  << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT][0], reqExt));
    957 	}
    958 	else
    959 	{
    960 		DE_ASSERT(m_spec.caseType == CASETYPE_COMPLETE);
    961 
    962 		const int	maxPatchVertices	= isTessellationPresent(m_spec) && isTessellationSupported(m_renderCtx, m_contextInfo)
    963 										? m_contextInfo.getInt(GL_MAX_PATCH_VERTICES) : 0;
    964 
    965 		for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
    966 		{
    967 			const ProgramSpecializationParams	progSpecParams	(m_spec, checkAndSpecializeExtensions(m_spec.programs[progNdx].requiredExtensions, m_contextInfo), maxPatchVertices);
    968 
    969 			specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
    970 		}
    971 	}
    972 
    973 	if (!separablePrograms)
    974 	{
    975 		de::SharedPtr<glu::ShaderProgram>	program		(new glu::ShaderProgram(m_renderCtx, specializedSources[0]));
    976 
    977 		vertexProgramID = program->getProgram();
    978 		pipelineProgramIDs.push_back(program->getProgram());
    979 		programs.push_back(program);
    980 
    981 		// Check that compile/link results are what we expect.
    982 
    983 		DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
    984 		for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
    985 			if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
    986 				allCompilesOk = false;
    987 
    988 		if (!program->getProgramInfo().linkOk)
    989 			allLinksOk = false;
    990 
    991 		log << *program;
    992 	}
    993 	else
    994 	{
    995 		// Separate programs
    996 		for (size_t programNdx = 0; programNdx < m_spec.programs.size(); ++programNdx)
    997 		{
    998 			de::SharedPtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_renderCtx, specializedSources[programNdx]));
    999 
   1000 			if (m_spec.programs[programNdx].activeStages & (1u << glu::SHADERTYPE_VERTEX))
   1001 				vertexProgramID = program->getProgram();
   1002 
   1003 			pipelineProgramIDs.push_back(program->getProgram());
   1004 			programs.push_back(program);
   1005 
   1006 			// Check that compile/link results are what we expect.
   1007 
   1008 			DE_STATIC_ASSERT(glu::SHADERTYPE_VERTEX == 0);
   1009 			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
   1010 				if (program->hasShader((glu::ShaderType)stage) && !program->getShaderInfo((glu::ShaderType)stage).compileOk)
   1011 					allCompilesOk = false;
   1012 
   1013 			if (!program->getProgramInfo().linkOk)
   1014 				allLinksOk = false;
   1015 
   1016 			// Log program and active stages
   1017 			{
   1018 				const tcu::ScopedLogSection	section		(log, "Program", "Program " + de::toString(programNdx+1));
   1019 				tcu::MessageBuilder			builder		(&log);
   1020 				bool						firstStage	= true;
   1021 
   1022 				builder << "Pipeline uses stages: ";
   1023 				for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
   1024 				{
   1025 					if (m_spec.programs[programNdx].activeStages & (1u << stage))
   1026 					{
   1027 						if (!firstStage)
   1028 							builder << ", ";
   1029 						builder << glu::getShaderTypeName((glu::ShaderType)stage);
   1030 						firstStage = true;
   1031 					}
   1032 				}
   1033 				builder << tcu::TestLog::EndMessage;
   1034 
   1035 				log << *program;
   1036 			}
   1037 		}
   1038 	}
   1039 
   1040 	switch (m_spec.expectResult)
   1041 	{
   1042 		case EXPECT_PASS:
   1043 		case EXPECT_VALIDATION_FAIL:
   1044 		case EXPECT_BUILD_SUCCESSFUL:
   1045 			if (!allCompilesOk)
   1046 				failReason = "expected shaders to compile and link properly, but failed to compile.";
   1047 			else if (!allLinksOk)
   1048 				failReason = "expected shaders to compile and link properly, but failed to link.";
   1049 			break;
   1050 
   1051 		case EXPECT_COMPILE_FAIL:
   1052 			if (allCompilesOk && !allLinksOk)
   1053 				failReason = "expected compilation to fail, but shaders compiled and link failed.";
   1054 			else if (allCompilesOk)
   1055 				failReason = "expected compilation to fail, but shaders compiled correctly.";
   1056 			break;
   1057 
   1058 		case EXPECT_LINK_FAIL:
   1059 			if (!allCompilesOk)
   1060 				failReason = "expected linking to fail, but unable to compile.";
   1061 			else if (allLinksOk)
   1062 				failReason = "expected linking to fail, but passed.";
   1063 			break;
   1064 
   1065 		case EXPECT_COMPILE_LINK_FAIL:
   1066 			if (allCompilesOk && allLinksOk)
   1067 				failReason = "expected compile or link to fail, but passed.";
   1068 			break;
   1069 
   1070 		default:
   1071 			DE_ASSERT(false);
   1072 			return false;
   1073 	}
   1074 
   1075 	if (failReason != DE_NULL)
   1076 	{
   1077 		// \todo [2010-06-07 petri] These should be handled in the test case?
   1078 		log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
   1079 
   1080 		if (m_spec.fullGLSLES100Required)
   1081 		{
   1082 			log	<< TestLog::Message
   1083 				<< "Assuming build failure is caused by implementation not supporting full GLSL ES 100 specification, which is not required."
   1084 				<< TestLog::EndMessage;
   1085 
   1086 			if (allCompilesOk && !allLinksOk)
   1087 			{
   1088 				// Used features are detectable at compile time. If implementation parses shader
   1089 				// at link time, report it as quality warning.
   1090 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
   1091 			}
   1092 			else
   1093 				m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Full GLSL ES 100 is not supported");
   1094 		}
   1095 		else if (m_spec.expectResult == EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
   1096 		{
   1097 			// If implementation parses shader at link time, report it as quality warning.
   1098 			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, failReason);
   1099 		}
   1100 		else
   1101 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason);
   1102 		return false;
   1103 	}
   1104 
   1105 	// Return if shader is not intended to be run
   1106 	if (m_spec.expectResult == EXPECT_COMPILE_FAIL		||
   1107 		m_spec.expectResult == EXPECT_COMPILE_LINK_FAIL	||
   1108 		m_spec.expectResult == EXPECT_LINK_FAIL			||
   1109 		m_spec.expectResult == EXPECT_BUILD_SUCCESSFUL)
   1110 		return true;
   1111 
   1112 	// Setup viewport.
   1113 	gl.viewport(viewportX, viewportY, width, height);
   1114 
   1115 	if (separablePrograms)
   1116 	{
   1117 		programPipeline = de::SharedPtr<glu::ProgramPipeline>(new glu::ProgramPipeline(m_renderCtx));
   1118 
   1119 		// Setup pipeline
   1120 		gl.bindProgramPipeline(programPipeline->getPipeline());
   1121 		for (int programNdx = 0; programNdx < (int)m_spec.programs.size(); ++programNdx)
   1122 		{
   1123 			deUint32 shaderFlags = 0;
   1124 			for (int stage = glu::SHADERTYPE_VERTEX; stage < glu::SHADERTYPE_LAST; ++stage)
   1125 				if (m_spec.programs[programNdx].activeStages & (1u << stage))
   1126 					shaderFlags |= glu::getGLShaderTypeBit((glu::ShaderType)stage);
   1127 
   1128 			programPipeline->useProgramStages(shaderFlags, pipelineProgramIDs[programNdx]);
   1129 		}
   1130 
   1131 		programPipeline->activeShaderProgram(vertexProgramID);
   1132 		GLU_EXPECT_NO_ERROR(gl.getError(), "setup pipeline");
   1133 	}
   1134 	else
   1135 	{
   1136 		// Start using program
   1137 		gl.useProgram(vertexProgramID);
   1138 		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
   1139 	}
   1140 
   1141 	// Fetch location for positions positions.
   1142 	int positionLoc = gl.getAttribLocation(vertexProgramID, "dEQP_Position");
   1143 	if (positionLoc == -1)
   1144 	{
   1145 		string errStr = string("no location found for attribute 'dEQP_Position'");
   1146 		TCU_FAIL(errStr.c_str());
   1147 	}
   1148 
   1149 	// Iterate all value blocks.
   1150 	{
   1151 		const ValueBlock&	valueBlock		= m_spec.values;
   1152 
   1153 		// always render at least one pass even if there is no input/output data
   1154 		const int			numRenderPasses	= valueBlock.outputs.empty() ? 1 : (int)valueBlock.outputs[0].elements.size() / valueBlock.outputs[0].type.getScalarSize();
   1155 
   1156 		// Iterate all array sub-cases.
   1157 		for (int arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++)
   1158 		{
   1159 			vector<VertexArrayBinding>	vertexArrays;
   1160 			int							attribValueNdx		= 0;
   1161 			vector<vector<float> >		attribValues		(valueBlock.inputs.size());
   1162 			glw::GLenum					postDrawError;
   1163 			BeforeDrawValidator			beforeDrawValidator	(gl,
   1164 															 (separablePrograms) ? (programPipeline->getPipeline())			: (vertexProgramID),
   1165 															 (separablePrograms) ? (BeforeDrawValidator::TARGETTYPE_PIPELINE)	: (BeforeDrawValidator::TARGETTYPE_PROGRAM));
   1166 
   1167 			vertexArrays.push_back(va::Float(positionLoc, 4, numVerticesPerDraw, 0, &s_positions[0]));
   1168 
   1169 			// Collect VA pointer for inputs
   1170 			for (size_t valNdx = 0; valNdx < valueBlock.inputs.size(); valNdx++)
   1171 			{
   1172 				const Value&		val			= valueBlock.inputs[valNdx];
   1173 				const char* const	valueName	= val.name.c_str();
   1174 				const DataType		dataType	= val.type.getBasicType();
   1175 				const int			scalarSize	= getDataTypeScalarSize(dataType);
   1176 
   1177 				// Replicate values four times.
   1178 				std::vector<float>& scalars = attribValues[attribValueNdx++];
   1179 				scalars.resize(numVerticesPerDraw * scalarSize);
   1180 				if (isDataTypeFloatOrVec(dataType) || isDataTypeMatrix(dataType))
   1181 				{
   1182 					for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
   1183 						for (int ndx = 0; ndx < scalarSize; ndx++)
   1184 							scalars[repNdx*scalarSize + ndx] = val.elements[arrayNdx*scalarSize + ndx].float32;
   1185 				}
   1186 				else
   1187 				{
   1188 					// convert to floats.
   1189 					for (int repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
   1190 					{
   1191 						for (int ndx = 0; ndx < scalarSize; ndx++)
   1192 						{
   1193 							float v = (float)val.elements[arrayNdx*scalarSize + ndx].int32;
   1194 							DE_ASSERT(val.elements[arrayNdx*scalarSize + ndx].int32 == (int)v);
   1195 							scalars[repNdx*scalarSize + ndx] = v;
   1196 						}
   1197 					}
   1198 				}
   1199 
   1200 				// Attribute name prefix.
   1201 				string attribPrefix = "";
   1202 				// \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
   1203 				if ((m_spec.caseType == CASETYPE_FRAGMENT_ONLY) || (getDataTypeScalarType(dataType) != TYPE_FLOAT))
   1204 					attribPrefix = "a_";
   1205 
   1206 				// Input always given as attribute.
   1207 				string attribName = attribPrefix + valueName;
   1208 				int attribLoc = gl.getAttribLocation(vertexProgramID, attribName.c_str());
   1209 				if (attribLoc == -1)
   1210 				{
   1211 					log << TestLog::Message << "Warning: no location found for attribute '" << attribName << "'" << TestLog::EndMessage;
   1212 					continue;
   1213 				}
   1214 
   1215 				if (isDataTypeMatrix(dataType))
   1216 				{
   1217 					int numCols = getDataTypeMatrixNumColumns(dataType);
   1218 					int numRows = getDataTypeMatrixNumRows(dataType);
   1219 					DE_ASSERT(scalarSize == numCols*numRows);
   1220 
   1221 					for (int i = 0; i < numCols; i++)
   1222 						vertexArrays.push_back(va::Float(attribLoc + i, numRows, numVerticesPerDraw, scalarSize*(int)sizeof(float), &scalars[i * numRows]));
   1223 				}
   1224 				else
   1225 				{
   1226 					DE_ASSERT(isDataTypeFloatOrVec(dataType) || isDataTypeIntOrIVec(dataType) || isDataTypeUintOrUVec(dataType) || isDataTypeBoolOrBVec(dataType));
   1227 					vertexArrays.push_back(va::Float(attribLoc, scalarSize, numVerticesPerDraw, 0, &scalars[0]));
   1228 				}
   1229 
   1230 				GLU_EXPECT_NO_ERROR(gl.getError(), "set vertex attrib array");
   1231 			}
   1232 
   1233 			GLU_EXPECT_NO_ERROR(gl.getError(), "before set uniforms");
   1234 
   1235 			// set reference values for outputs.
   1236 			for (size_t valNdx = 0; valNdx < valueBlock.outputs.size(); valNdx++)
   1237 			{
   1238 				const Value&		val			= valueBlock.outputs[valNdx];
   1239 				const char* const	valueName	= val.name.c_str();
   1240 
   1241 				// Set reference value.
   1242 				string refName = string("ref_") + valueName;
   1243 				setUniformValue(gl, pipelineProgramIDs, refName, val, arrayNdx, m_testCtx.getLog());
   1244 				GLU_EXPECT_NO_ERROR(gl.getError(), "set reference uniforms");
   1245 			}
   1246 
   1247 			// set uniform values
   1248 			for (size_t valNdx = 0; valNdx < valueBlock.uniforms.size(); valNdx++)
   1249 			{
   1250 				const Value&		val			= valueBlock.uniforms[valNdx];
   1251 				const char* const	valueName	= val.name.c_str();
   1252 
   1253 				setUniformValue(gl, pipelineProgramIDs, valueName, val, arrayNdx, m_testCtx.getLog());
   1254 				GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
   1255 			}
   1256 
   1257 			// Clear.
   1258 			gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
   1259 			gl.clear(GL_COLOR_BUFFER_BIT);
   1260 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
   1261 
   1262 			// Use program or pipeline
   1263 			if (separablePrograms)
   1264 				gl.useProgram(0);
   1265 			else
   1266 				gl.useProgram(vertexProgramID);
   1267 
   1268 			// Draw.
   1269 			if (tessellationPresent)
   1270 			{
   1271 				gl.patchParameteri(GL_PATCH_VERTICES, 3);
   1272 				GLU_EXPECT_NO_ERROR(gl.getError(), "set patchParameteri(PATCH_VERTICES, 3)");
   1273 			}
   1274 
   1275 			draw(m_renderCtx,
   1276 				 vertexProgramID,
   1277 				 (int)vertexArrays.size(),
   1278 				 &vertexArrays[0],
   1279 				 (tessellationPresent) ?
   1280 					(pr::Patches(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])) :
   1281 					(pr::Triangles(DE_LENGTH_OF_ARRAY(s_indices), &s_indices[0])),
   1282 				 (m_spec.expectResult == EXPECT_VALIDATION_FAIL) ?
   1283 					(&beforeDrawValidator) :
   1284 					(DE_NULL));
   1285 
   1286 			postDrawError = gl.getError();
   1287 
   1288 			if (m_spec.expectResult == EXPECT_PASS)
   1289 			{
   1290 				// Read back results.
   1291 				Surface			surface			(width, height);
   1292 				const float		w				= s_positions[3];
   1293 				const int		minY			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)height + 1.0f);
   1294 				const int		maxY			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)height - 0.5f);
   1295 				const int		minX			= deCeilFloatToInt32 (((-quadSize / w) * 0.5f + 0.5f) * (float)width + 1.0f);
   1296 				const int		maxX			= deFloorFloatToInt32(((+quadSize / w) * 0.5f + 0.5f) * (float)width - 0.5f);
   1297 
   1298 				GLU_EXPECT_NO_ERROR(postDrawError, "draw");
   1299 
   1300 				glu::readPixels(m_renderCtx, viewportX, viewportY, surface.getAccess());
   1301 				GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
   1302 
   1303 				if (!checkPixels(log, tcu::getSubregion(surface.getAccess(), minX, minY, maxX-minX+1, maxY-minY+1)))
   1304 				{
   1305 					log << TestLog::Message << "INCORRECT RESULT for sub-case " << arrayNdx+1 << " of " << numRenderPasses << "):"
   1306 						<< TestLog::EndMessage;
   1307 
   1308 					log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
   1309 					dumpValues(log, valueBlock, arrayNdx);
   1310 
   1311 					// Dump image on failure.
   1312 					log << TestLog::Image("Result", "Rendered result image", surface);
   1313 
   1314 					gl.useProgram(0);
   1315 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1316 					return false;
   1317 				}
   1318 			}
   1319 			else if (m_spec.expectResult == EXPECT_VALIDATION_FAIL)
   1320 			{
   1321 				log	<< TestLog::Message
   1322 					<< "Draw call generated error: "
   1323 					<< glu::getErrorStr(postDrawError) << " "
   1324 					<< ((postDrawError == GL_INVALID_OPERATION) ? ("(expected)") : ("(unexpected)")) << "\n"
   1325 					<< "Validate status: "
   1326 					<< glu::getBooleanStr(beforeDrawValidator.getValidateStatus()) << " "
   1327 					<< ((beforeDrawValidator.getValidateStatus() == GL_FALSE) ? ("(expected)") : ("(unexpected)")) << "\n"
   1328 					<< "Info log: "
   1329 					<< ((beforeDrawValidator.getInfoLog().empty()) ? ("[empty string]") : (beforeDrawValidator.getInfoLog())) << "\n"
   1330 					<< TestLog::EndMessage;
   1331 
   1332 				// test result
   1333 
   1334 				if (postDrawError != GL_NO_ERROR && postDrawError != GL_INVALID_OPERATION)
   1335 				{
   1336 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, ("Draw: got unexpected error: " + de::toString(glu::getErrorStr(postDrawError))).c_str());
   1337 					return false;
   1338 				}
   1339 
   1340 				if (beforeDrawValidator.getValidateStatus() == GL_TRUE)
   1341 				{
   1342 					if (postDrawError == GL_NO_ERROR)
   1343 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation and rendering succeeded");
   1344 					else if (postDrawError == GL_INVALID_OPERATION)
   1345 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but validation succeeded (rendering failed as expected)");
   1346 					else
   1347 						DE_ASSERT(false);
   1348 					return false;
   1349 				}
   1350 				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_NO_ERROR)
   1351 				{
   1352 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "expected validation and rendering to fail but rendering succeeded (validation failed as expected)");
   1353 					return false;
   1354 				}
   1355 				else if (beforeDrawValidator.getValidateStatus() == GL_FALSE && postDrawError == GL_INVALID_OPERATION)
   1356 				{
   1357 					// Validation does not depend on input values, no need to test all values
   1358 					return true;
   1359 				}
   1360 				else
   1361 					DE_ASSERT(false);
   1362 			}
   1363 			else
   1364 				DE_ASSERT(false);
   1365 		}
   1366 	}
   1367 
   1368 	gl.useProgram(0);
   1369 	if (separablePrograms)
   1370 		gl.bindProgramPipeline(0);
   1371 
   1372 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderCase::execute(): end");
   1373 	return true;
   1374 }
   1375 
   1376 TestCase::IterateResult ShaderLibraryCase::iterate (void)
   1377 {
   1378 	// Initialize state to pass.
   1379 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1380 
   1381 	bool executeOk = execute();
   1382 
   1383 	DE_ASSERT(executeOk ? m_testCtx.getTestResult() == QP_TEST_RESULT_PASS : m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
   1384 	DE_UNREF(executeOk);
   1385 	return TestCase::STOP;
   1386 }
   1387 
   1388 } // gls
   1389 } // deqp
   1390