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