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