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
53namespace deqp
54{
55namespace gls
56{
57
58using namespace tcu;
59using namespace glu;
60using namespace glu::sl;
61
62using std::vector;
63using std::string;
64using std::ostringstream;
65using std::map;
66using std::pair;
67
68using de::SharedPtr;
69
70// OpenGL-specific specialization utils
71
72static 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
117static 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'.
140static 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
192static 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
226static inline bool supportsFragmentHighp (glu::GLSLVersion version)
227{
228	return version != glu::GLSL_VERSION_100_ES;
229}
230
231static 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.
283static 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.
356static 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
422static 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
434static 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
473static 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
506static 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
522static 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
548static 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
568static 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
589static 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
602enum
603{
604	VIEWPORT_WIDTH		= 128,
605	VIEWPORT_HEIGHT		= 128
606};
607
608class BeforeDrawValidator : public glu::DrawUtilCallback
609{
610public:
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
626private:
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
635BeforeDrawValidator::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
644void 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
707const std::string& BeforeDrawValidator::getInfoLog (void) const
708{
709	return m_logMessage;
710}
711
712glw::GLint BeforeDrawValidator::getValidateStatus (void) const
713{
714	return m_validateStatus;
715}
716
717// ShaderCase.
718
719ShaderLibraryCase::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
727ShaderLibraryCase::~ShaderLibraryCase (void)
728{
729}
730
731static 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
737void 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
796static 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
861static 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
878static 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
892static 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
927bool 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
1419TestCase::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