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