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 Shader execution utilities.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "glsShaderExecUtil.hpp"
25e5c31af7Sopenharmony_ci#include "gluRenderContext.hpp"
26e5c31af7Sopenharmony_ci#include "gluDrawUtil.hpp"
27e5c31af7Sopenharmony_ci#include "gluObjectWrapper.hpp"
28e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp"
29e5c31af7Sopenharmony_ci#include "gluTextureUtil.hpp"
30e5c31af7Sopenharmony_ci#include "gluProgramInterfaceQuery.hpp"
31e5c31af7Sopenharmony_ci#include "gluPixelTransfer.hpp"
32e5c31af7Sopenharmony_ci#include "gluStrUtil.hpp"
33e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
34e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
35e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
36e5c31af7Sopenharmony_ci#include "deSTLUtil.hpp"
37e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
38e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp"
39e5c31af7Sopenharmony_ci#include "deMemory.h"
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ci#include <map>
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_cinamespace deqp
44e5c31af7Sopenharmony_ci{
45e5c31af7Sopenharmony_cinamespace gls
46e5c31af7Sopenharmony_ci{
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_cinamespace ShaderExecUtil
49e5c31af7Sopenharmony_ci{
50e5c31af7Sopenharmony_ci
51e5c31af7Sopenharmony_ciusing std::vector;
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_cistatic bool isExtensionSupported (const glu::RenderContext& renderCtx, const std::string& extension)
54e5c31af7Sopenharmony_ci{
55e5c31af7Sopenharmony_ci	const glw::Functions&	gl		= renderCtx.getFunctions();
56e5c31af7Sopenharmony_ci	int						numExts	= 0;
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_ci	gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numExts; ndx++)
61e5c31af7Sopenharmony_ci	{
62e5c31af7Sopenharmony_ci		const char* curExt = (const char*)gl.getStringi(GL_EXTENSIONS, ndx);
63e5c31af7Sopenharmony_ci
64e5c31af7Sopenharmony_ci		if (extension == curExt)
65e5c31af7Sopenharmony_ci			return true;
66e5c31af7Sopenharmony_ci	}
67e5c31af7Sopenharmony_ci
68e5c31af7Sopenharmony_ci	return false;
69e5c31af7Sopenharmony_ci}
70e5c31af7Sopenharmony_ci
71e5c31af7Sopenharmony_cistatic void checkExtension (const glu::RenderContext& renderCtx, const std::string& extension)
72e5c31af7Sopenharmony_ci{
73e5c31af7Sopenharmony_ci	if (!isExtensionSupported(renderCtx, extension))
74e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError(extension + " is not supported");
75e5c31af7Sopenharmony_ci}
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_cistatic void checkLimit (const glu::RenderContext& renderCtx, deUint32 pname, int required)
78e5c31af7Sopenharmony_ci{
79e5c31af7Sopenharmony_ci	const glw::Functions&	gl					= renderCtx.getFunctions();
80e5c31af7Sopenharmony_ci	int						implementationLimit	= -1;
81e5c31af7Sopenharmony_ci	deUint32				error;
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ci	gl.getIntegerv(pname, &implementationLimit);
84e5c31af7Sopenharmony_ci	error = gl.getError();
85e5c31af7Sopenharmony_ci
86e5c31af7Sopenharmony_ci	if (error != GL_NO_ERROR)
87e5c31af7Sopenharmony_ci		throw tcu::TestError("Failed to query " + de::toString(glu::getGettableStateStr(pname)) + " - got " + de::toString(glu::getErrorStr(error)));
88e5c31af7Sopenharmony_ci	if (implementationLimit < required)
89e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " >= " + de::toString(required) + ", got " + de::toString(implementationLimit));
90e5c31af7Sopenharmony_ci}
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci// Shader utilities
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_cistatic std::string generateVertexShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix)
95e5c31af7Sopenharmony_ci{
96e5c31af7Sopenharmony_ci	const bool			usesInout	= glu::glslVersionUsesInOutQualifiers(shaderSpec.version);
97e5c31af7Sopenharmony_ci	const char*			in			= usesInout ? "in"		: "attribute";
98e5c31af7Sopenharmony_ci	const char*			out			= usesInout ? "out"		: "varying";
99e5c31af7Sopenharmony_ci	std::ostringstream	src;
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci	DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
104e5c31af7Sopenharmony_ci
105e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
106e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ci	src << in << " highp vec4 a_position;\n";
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
111e5c31af7Sopenharmony_ci		src << in << " " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
114e5c31af7Sopenharmony_ci	{
115e5c31af7Sopenharmony_ci		DE_ASSERT(output->varType.isBasicType());
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ci		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
118e5c31af7Sopenharmony_ci		{
119e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
120e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
121e5c31af7Sopenharmony_ci			const glu::VarType		intType		(intBaseType, glu::PRECISION_HIGHP);
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ci			src << "flat " << out << " " << glu::declare(intType, outputPrefix + output->name) << ";\n";
124e5c31af7Sopenharmony_ci		}
125e5c31af7Sopenharmony_ci		else
126e5c31af7Sopenharmony_ci			src << "flat " << out << " " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
127e5c31af7Sopenharmony_ci	}
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci	src << "\n"
130e5c31af7Sopenharmony_ci		<< "void main (void)\n"
131e5c31af7Sopenharmony_ci		<< "{\n"
132e5c31af7Sopenharmony_ci		<< "	gl_Position = a_position;\n"
133e5c31af7Sopenharmony_ci		<< "	gl_PointSize = 1.0;\n\n";
134e5c31af7Sopenharmony_ci
135e5c31af7Sopenharmony_ci	// Declare & fetch local input variables
136e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
137e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
138e5c31af7Sopenharmony_ci
139e5c31af7Sopenharmony_ci	// Declare local output variables
140e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
141e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(output->varType, output->name) << ";\n";
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ci	// Operation - indented to correct level.
144e5c31af7Sopenharmony_ci	{
145e5c31af7Sopenharmony_ci		std::istringstream	opSrc	(shaderSpec.source);
146e5c31af7Sopenharmony_ci		std::string			line;
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci		while (std::getline(opSrc, line))
149e5c31af7Sopenharmony_ci			src << "\t" << line << "\n";
150e5c31af7Sopenharmony_ci	}
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci	// Assignments to outputs.
153e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
154e5c31af7Sopenharmony_ci	{
155e5c31af7Sopenharmony_ci		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
156e5c31af7Sopenharmony_ci		{
157e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
158e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
161e5c31af7Sopenharmony_ci		}
162e5c31af7Sopenharmony_ci		else
163e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
164e5c31af7Sopenharmony_ci	}
165e5c31af7Sopenharmony_ci
166e5c31af7Sopenharmony_ci	src << "}\n";
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci	return src.str();
169e5c31af7Sopenharmony_ci}
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_cistatic std::string generateGeometryShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix)
172e5c31af7Sopenharmony_ci{
173e5c31af7Sopenharmony_ci	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
174e5c31af7Sopenharmony_ci	DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
175e5c31af7Sopenharmony_ci
176e5c31af7Sopenharmony_ci	std::ostringstream	src;
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
179e5c31af7Sopenharmony_ci
180e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
181e5c31af7Sopenharmony_ci		src << "#extension GL_EXT_geometry_shader : require\n";
182e5c31af7Sopenharmony_ci
183e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
184e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci	src << "layout(points) in;\n"
187e5c31af7Sopenharmony_ci		<< "layout(points, max_vertices = 1) out;\n";
188e5c31af7Sopenharmony_ci
189e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
190e5c31af7Sopenharmony_ci		src << "flat in " << glu::declare(input->varType, inputPrefix + input->name) << "[];\n";
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
193e5c31af7Sopenharmony_ci	{
194e5c31af7Sopenharmony_ci		DE_ASSERT(output->varType.isBasicType());
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_ci		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
197e5c31af7Sopenharmony_ci		{
198e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
199e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
200e5c31af7Sopenharmony_ci			const glu::VarType		intType		(intBaseType, glu::PRECISION_HIGHP);
201e5c31af7Sopenharmony_ci
202e5c31af7Sopenharmony_ci			src << "flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n";
203e5c31af7Sopenharmony_ci		}
204e5c31af7Sopenharmony_ci		else
205e5c31af7Sopenharmony_ci			src << "flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
206e5c31af7Sopenharmony_ci	}
207e5c31af7Sopenharmony_ci
208e5c31af7Sopenharmony_ci	src << "\n"
209e5c31af7Sopenharmony_ci		<< "void main (void)\n"
210e5c31af7Sopenharmony_ci		<< "{\n"
211e5c31af7Sopenharmony_ci		<< "	gl_Position = gl_in[0].gl_Position;\n\n";
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci	// Fetch input variables
214e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
215e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << "[0];\n";
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_ci	// Declare local output variables.
218e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
219e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(output->varType, output->name) << ";\n";
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci	src << "\n";
222e5c31af7Sopenharmony_ci
223e5c31af7Sopenharmony_ci	// Operation - indented to correct level.
224e5c31af7Sopenharmony_ci	{
225e5c31af7Sopenharmony_ci		std::istringstream	opSrc	(shaderSpec.source);
226e5c31af7Sopenharmony_ci		std::string			line;
227e5c31af7Sopenharmony_ci
228e5c31af7Sopenharmony_ci		while (std::getline(opSrc, line))
229e5c31af7Sopenharmony_ci			src << "\t" << line << "\n";
230e5c31af7Sopenharmony_ci	}
231e5c31af7Sopenharmony_ci
232e5c31af7Sopenharmony_ci	// Assignments to outputs.
233e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
234e5c31af7Sopenharmony_ci	{
235e5c31af7Sopenharmony_ci		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
236e5c31af7Sopenharmony_ci		{
237e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
238e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
241e5c31af7Sopenharmony_ci		}
242e5c31af7Sopenharmony_ci		else
243e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
244e5c31af7Sopenharmony_ci	}
245e5c31af7Sopenharmony_ci
246e5c31af7Sopenharmony_ci	src << "	EmitVertex();\n"
247e5c31af7Sopenharmony_ci		<< "	EndPrimitive();\n"
248e5c31af7Sopenharmony_ci		<< "}\n";
249e5c31af7Sopenharmony_ci
250e5c31af7Sopenharmony_ci	return src.str();
251e5c31af7Sopenharmony_ci}
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_cistatic std::string generateEmptyFragmentSource (glu::GLSLVersion version)
254e5c31af7Sopenharmony_ci{
255e5c31af7Sopenharmony_ci	const bool			customOut		= glu::glslVersionUsesInOutQualifiers(version);
256e5c31af7Sopenharmony_ci	std::ostringstream	src;
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(version) << "\n";
259e5c31af7Sopenharmony_ci
260e5c31af7Sopenharmony_ci	// \todo [2013-08-05 pyry] Do we need one unused output?
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ci	src << "void main (void)\n{\n";
263e5c31af7Sopenharmony_ci	if (!customOut)
264e5c31af7Sopenharmony_ci		src << "	gl_FragColor = vec4(0.0);\n";
265e5c31af7Sopenharmony_ci	src << "}\n";
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci	return src.str();
268e5c31af7Sopenharmony_ci}
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_cistatic std::string generatePassthroughVertexShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix)
271e5c31af7Sopenharmony_ci{
272e5c31af7Sopenharmony_ci	// flat qualifier is not present in earlier versions?
273e5c31af7Sopenharmony_ci	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_ci	std::ostringstream src;
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"
278e5c31af7Sopenharmony_ci		<< "in highp vec4 a_position;\n";
279e5c31af7Sopenharmony_ci
280e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
281e5c31af7Sopenharmony_ci	{
282e5c31af7Sopenharmony_ci		src << "in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"
283e5c31af7Sopenharmony_ci			<< "flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n";
284e5c31af7Sopenharmony_ci	}
285e5c31af7Sopenharmony_ci
286e5c31af7Sopenharmony_ci	src << "\nvoid main (void)\n{\n"
287e5c31af7Sopenharmony_ci		<< "	gl_Position = a_position;\n"
288e5c31af7Sopenharmony_ci		<< "	gl_PointSize = 1.0;\n";
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
291e5c31af7Sopenharmony_ci		src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n";
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci	src << "}\n";
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci	return src.str();
296e5c31af7Sopenharmony_ci}
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_cistatic void generateFragShaderOutputDecl (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& outputPrefix)
299e5c31af7Sopenharmony_ci{
300e5c31af7Sopenharmony_ci	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci	for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx)
303e5c31af7Sopenharmony_ci	{
304e5c31af7Sopenharmony_ci		const Symbol&				output		= shaderSpec.outputs[outNdx];
305e5c31af7Sopenharmony_ci		const int					location	= de::lookup(outLocationMap, output.name);
306e5c31af7Sopenharmony_ci		const std::string			outVarName	= outputPrefix + output.name;
307e5c31af7Sopenharmony_ci		glu::VariableDeclaration	decl		(output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(location));
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci		TCU_CHECK_INTERNAL(output.varType.isBasicType());
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci		if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType()))
312e5c31af7Sopenharmony_ci		{
313e5c31af7Sopenharmony_ci			const int			vecSize			= glu::getDataTypeScalarSize(output.varType.getBasicType());
314e5c31af7Sopenharmony_ci			const glu::DataType	uintBasicType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
315e5c31af7Sopenharmony_ci			const glu::VarType	uintType		(uintBasicType, glu::PRECISION_HIGHP);
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_ci			decl.varType = uintType;
318e5c31af7Sopenharmony_ci			src << decl << ";\n";
319e5c31af7Sopenharmony_ci		}
320e5c31af7Sopenharmony_ci		else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType()))
321e5c31af7Sopenharmony_ci		{
322e5c31af7Sopenharmony_ci			const int			vecSize			= glu::getDataTypeScalarSize(output.varType.getBasicType());
323e5c31af7Sopenharmony_ci			const glu::DataType	intBasicType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
324e5c31af7Sopenharmony_ci			const glu::VarType	intType			(intBasicType, glu::PRECISION_HIGHP);
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci			decl.varType = intType;
327e5c31af7Sopenharmony_ci			src << decl << ";\n";
328e5c31af7Sopenharmony_ci		}
329e5c31af7Sopenharmony_ci		else if (glu::isDataTypeMatrix(output.varType.getBasicType()))
330e5c31af7Sopenharmony_ci		{
331e5c31af7Sopenharmony_ci			const int			vecSize			= glu::getDataTypeMatrixNumRows(output.varType.getBasicType());
332e5c31af7Sopenharmony_ci			const int			numVecs			= glu::getDataTypeMatrixNumColumns(output.varType.getBasicType());
333e5c31af7Sopenharmony_ci			const glu::DataType	uintBasicType	= glu::getDataTypeUintVec(vecSize);
334e5c31af7Sopenharmony_ci			const glu::VarType	uintType		(uintBasicType, glu::PRECISION_HIGHP);
335e5c31af7Sopenharmony_ci
336e5c31af7Sopenharmony_ci			decl.varType = uintType;
337e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
338e5c31af7Sopenharmony_ci			{
339e5c31af7Sopenharmony_ci				decl.name				= outVarName + "_" + de::toString(vecNdx);
340e5c31af7Sopenharmony_ci				decl.layout.location	= location + vecNdx;
341e5c31af7Sopenharmony_ci				src << decl << ";\n";
342e5c31af7Sopenharmony_ci			}
343e5c31af7Sopenharmony_ci		}
344e5c31af7Sopenharmony_ci		else
345e5c31af7Sopenharmony_ci			src << decl << ";\n";
346e5c31af7Sopenharmony_ci	}
347e5c31af7Sopenharmony_ci}
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_cistatic void generateFragShaderOutAssign (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::string& valuePrefix, const std::string& outputPrefix)
350e5c31af7Sopenharmony_ci{
351e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
352e5c31af7Sopenharmony_ci	{
353e5c31af7Sopenharmony_ci		if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType()))
354e5c31af7Sopenharmony_ci			src << "	o_" << output->name << " = floatBitsToUint(" << valuePrefix << output->name << ");\n";
355e5c31af7Sopenharmony_ci		else if (glu::isDataTypeMatrix(output->varType.getBasicType()))
356e5c31af7Sopenharmony_ci		{
357e5c31af7Sopenharmony_ci			const int	numVecs		= glu::getDataTypeMatrixNumColumns(output->varType.getBasicType());
358e5c31af7Sopenharmony_ci
359e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
360e5c31af7Sopenharmony_ci				if (useIntOutputs)
361e5c31af7Sopenharmony_ci					src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = floatBitsToUint(" << valuePrefix << output->name << "[" << vecNdx << "]);\n";
362e5c31af7Sopenharmony_ci				else
363e5c31af7Sopenharmony_ci					src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = " << valuePrefix << output->name << "[" << vecNdx << "];\n";
364e5c31af7Sopenharmony_ci		}
365e5c31af7Sopenharmony_ci		else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
366e5c31af7Sopenharmony_ci		{
367e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
368e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << valuePrefix << output->name << ");\n";
371e5c31af7Sopenharmony_ci		}
372e5c31af7Sopenharmony_ci		else
373e5c31af7Sopenharmony_ci			src << "\t" << outputPrefix << output->name << " = " << valuePrefix << output->name << ";\n";
374e5c31af7Sopenharmony_ci	}
375e5c31af7Sopenharmony_ci}
376e5c31af7Sopenharmony_ci
377e5c31af7Sopenharmony_cistatic std::string generateFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix)
378e5c31af7Sopenharmony_ci{
379e5c31af7Sopenharmony_ci	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
380e5c31af7Sopenharmony_ci
381e5c31af7Sopenharmony_ci	std::ostringstream	src;
382e5c31af7Sopenharmony_ci
383e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
386e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
387e5c31af7Sopenharmony_ci
388e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
389e5c31af7Sopenharmony_ci		src << "flat in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
390e5c31af7Sopenharmony_ci
391e5c31af7Sopenharmony_ci	generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci	src << "\nvoid main (void)\n{\n";
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_ci	// Declare & fetch local input variables
396e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
397e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
398e5c31af7Sopenharmony_ci
399e5c31af7Sopenharmony_ci	// Declare output variables
400e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
401e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(output->varType, output->name) << ";\n";
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	// Operation - indented to correct level.
404e5c31af7Sopenharmony_ci	{
405e5c31af7Sopenharmony_ci		std::istringstream	opSrc	(shaderSpec.source);
406e5c31af7Sopenharmony_ci		std::string			line;
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci		while (std::getline(opSrc, line))
409e5c31af7Sopenharmony_ci			src << "\t" << line << "\n";
410e5c31af7Sopenharmony_ci	}
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_ci	generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, "", outputPrefix);
413e5c31af7Sopenharmony_ci
414e5c31af7Sopenharmony_ci	src << "}\n";
415e5c31af7Sopenharmony_ci
416e5c31af7Sopenharmony_ci	return src.str();
417e5c31af7Sopenharmony_ci}
418e5c31af7Sopenharmony_ci
419e5c31af7Sopenharmony_cistatic std::string generatePassthroughFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix)
420e5c31af7Sopenharmony_ci{
421e5c31af7Sopenharmony_ci	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci	std::ostringstream	src;
424e5c31af7Sopenharmony_ci
425e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
426e5c31af7Sopenharmony_ci
427e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
428e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
431e5c31af7Sopenharmony_ci	{
432e5c31af7Sopenharmony_ci		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
433e5c31af7Sopenharmony_ci		{
434e5c31af7Sopenharmony_ci			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
435e5c31af7Sopenharmony_ci			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
436e5c31af7Sopenharmony_ci			const glu::VarType		intType		(intBaseType, glu::PRECISION_HIGHP);
437e5c31af7Sopenharmony_ci
438e5c31af7Sopenharmony_ci			src << "flat in " << glu::declare(intType, inputPrefix + output->name) << ";\n";
439e5c31af7Sopenharmony_ci		}
440e5c31af7Sopenharmony_ci		else
441e5c31af7Sopenharmony_ci			src << "flat in " << glu::declare(output->varType, inputPrefix + output->name) << ";\n";
442e5c31af7Sopenharmony_ci	}
443e5c31af7Sopenharmony_ci
444e5c31af7Sopenharmony_ci	generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_ci	src << "\nvoid main (void)\n{\n";
447e5c31af7Sopenharmony_ci
448e5c31af7Sopenharmony_ci	generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, inputPrefix, outputPrefix);
449e5c31af7Sopenharmony_ci
450e5c31af7Sopenharmony_ci	src << "}\n";
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci	return src.str();
453e5c31af7Sopenharmony_ci}
454e5c31af7Sopenharmony_ci
455e5c31af7Sopenharmony_ci// ShaderExecutor
456e5c31af7Sopenharmony_ci
457e5c31af7Sopenharmony_ciShaderExecutor::ShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
458e5c31af7Sopenharmony_ci	: m_renderCtx	(renderCtx)
459e5c31af7Sopenharmony_ci	, m_inputs		(shaderSpec.inputs)
460e5c31af7Sopenharmony_ci	, m_outputs		(shaderSpec.outputs)
461e5c31af7Sopenharmony_ci{
462e5c31af7Sopenharmony_ci}
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_ciShaderExecutor::~ShaderExecutor (void)
465e5c31af7Sopenharmony_ci{
466e5c31af7Sopenharmony_ci}
467e5c31af7Sopenharmony_ci
468e5c31af7Sopenharmony_civoid ShaderExecutor::useProgram (void)
469e5c31af7Sopenharmony_ci{
470e5c31af7Sopenharmony_ci	DE_ASSERT(isOk());
471e5c31af7Sopenharmony_ci	m_renderCtx.getFunctions().useProgram(getProgram());
472e5c31af7Sopenharmony_ci}
473e5c31af7Sopenharmony_ci
474e5c31af7Sopenharmony_ci// FragmentOutExecutor
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_cistruct FragmentOutputLayout
477e5c31af7Sopenharmony_ci{
478e5c31af7Sopenharmony_ci	std::vector<const Symbol*>		locationSymbols;		//! Symbols by location
479e5c31af7Sopenharmony_ci	std::map<std::string, int>		locationMap;			//! Map from symbol name to start location
480e5c31af7Sopenharmony_ci};
481e5c31af7Sopenharmony_ci
482e5c31af7Sopenharmony_ciclass FragmentOutExecutor : public ShaderExecutor
483e5c31af7Sopenharmony_ci{
484e5c31af7Sopenharmony_cipublic:
485e5c31af7Sopenharmony_ci								FragmentOutExecutor		(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
486e5c31af7Sopenharmony_ci								~FragmentOutExecutor	(void);
487e5c31af7Sopenharmony_ci
488e5c31af7Sopenharmony_ci	void						execute					(int numValues, const void* const* inputs, void* const* outputs);
489e5c31af7Sopenharmony_ci
490e5c31af7Sopenharmony_ciprotected:
491e5c31af7Sopenharmony_ci	const FragmentOutputLayout	m_outputLayout;
492e5c31af7Sopenharmony_ci};
493e5c31af7Sopenharmony_ci
494e5c31af7Sopenharmony_cistatic FragmentOutputLayout computeFragmentOutputLayout (const std::vector<Symbol>& symbols)
495e5c31af7Sopenharmony_ci{
496e5c31af7Sopenharmony_ci	FragmentOutputLayout	ret;
497e5c31af7Sopenharmony_ci	int						location	= 0;
498e5c31af7Sopenharmony_ci
499e5c31af7Sopenharmony_ci	for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it)
500e5c31af7Sopenharmony_ci	{
501e5c31af7Sopenharmony_ci		const int	numLocations	= glu::getDataTypeNumLocations(it->varType.getBasicType());
502e5c31af7Sopenharmony_ci
503e5c31af7Sopenharmony_ci		TCU_CHECK_INTERNAL(!de::contains(ret.locationMap, it->name));
504e5c31af7Sopenharmony_ci		de::insert(ret.locationMap, it->name, location);
505e5c31af7Sopenharmony_ci		location += numLocations;
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_ci		for (int ndx = 0; ndx < numLocations; ++ndx)
508e5c31af7Sopenharmony_ci			ret.locationSymbols.push_back(&*it);
509e5c31af7Sopenharmony_ci	}
510e5c31af7Sopenharmony_ci
511e5c31af7Sopenharmony_ci	return ret;
512e5c31af7Sopenharmony_ci}
513e5c31af7Sopenharmony_ci
514e5c31af7Sopenharmony_ciinline bool hasFloatRenderTargets (const glu::RenderContext& renderCtx)
515e5c31af7Sopenharmony_ci{
516e5c31af7Sopenharmony_ci	glu::ContextType type = renderCtx.getType();
517e5c31af7Sopenharmony_ci	return glu::isContextTypeGLCore(type);
518e5c31af7Sopenharmony_ci}
519e5c31af7Sopenharmony_ci
520e5c31af7Sopenharmony_ciFragmentOutExecutor::FragmentOutExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
521e5c31af7Sopenharmony_ci	: ShaderExecutor	(renderCtx, shaderSpec)
522e5c31af7Sopenharmony_ci	, m_outputLayout	(computeFragmentOutputLayout(m_outputs))
523e5c31af7Sopenharmony_ci{
524e5c31af7Sopenharmony_ci}
525e5c31af7Sopenharmony_ci
526e5c31af7Sopenharmony_ciFragmentOutExecutor::~FragmentOutExecutor (void)
527e5c31af7Sopenharmony_ci{
528e5c31af7Sopenharmony_ci}
529e5c31af7Sopenharmony_ci
530e5c31af7Sopenharmony_ciinline int queryInt (const glw::Functions& gl, deUint32 pname)
531e5c31af7Sopenharmony_ci{
532e5c31af7Sopenharmony_ci	int value = 0;
533e5c31af7Sopenharmony_ci	gl.getIntegerv(pname, &value);
534e5c31af7Sopenharmony_ci	return value;
535e5c31af7Sopenharmony_ci}
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_cistatic tcu::TextureFormat getRenderbufferFormatForOutput (const glu::VarType& outputType, bool useIntOutputs)
538e5c31af7Sopenharmony_ci{
539e5c31af7Sopenharmony_ci	const tcu::TextureFormat::ChannelOrder channelOrderMap[] =
540e5c31af7Sopenharmony_ci	{
541e5c31af7Sopenharmony_ci		tcu::TextureFormat::R,
542e5c31af7Sopenharmony_ci		tcu::TextureFormat::RG,
543e5c31af7Sopenharmony_ci		tcu::TextureFormat::RGBA,	// No RGB variants available.
544e5c31af7Sopenharmony_ci		tcu::TextureFormat::RGBA
545e5c31af7Sopenharmony_ci	};
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci	const glu::DataType					basicType		= outputType.getBasicType();
548e5c31af7Sopenharmony_ci	const int							numComps		= glu::getDataTypeNumComponents(basicType);
549e5c31af7Sopenharmony_ci	tcu::TextureFormat::ChannelType		channelType;
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci	switch (glu::getDataTypeScalarType(basicType))
552e5c31af7Sopenharmony_ci	{
553e5c31af7Sopenharmony_ci		case glu::TYPE_UINT:	channelType = tcu::TextureFormat::UNSIGNED_INT32;												break;
554e5c31af7Sopenharmony_ci		case glu::TYPE_INT:		channelType = tcu::TextureFormat::SIGNED_INT32;													break;
555e5c31af7Sopenharmony_ci		case glu::TYPE_BOOL:	channelType = tcu::TextureFormat::SIGNED_INT32;													break;
556e5c31af7Sopenharmony_ci		case glu::TYPE_FLOAT:	channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT;	break;
557e5c31af7Sopenharmony_ci		default:
558e5c31af7Sopenharmony_ci			throw tcu::InternalError("Invalid output type");
559e5c31af7Sopenharmony_ci	}
560e5c31af7Sopenharmony_ci
561e5c31af7Sopenharmony_ci	DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap)));
562e5c31af7Sopenharmony_ci
563e5c31af7Sopenharmony_ci	return tcu::TextureFormat(channelOrderMap[numComps-1], channelType);
564e5c31af7Sopenharmony_ci}
565e5c31af7Sopenharmony_ci
566e5c31af7Sopenharmony_civoid FragmentOutExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
567e5c31af7Sopenharmony_ci{
568e5c31af7Sopenharmony_ci	const glw::Functions&			gl					= m_renderCtx.getFunctions();
569e5c31af7Sopenharmony_ci	const bool						useIntOutputs		= !hasFloatRenderTargets(m_renderCtx);
570e5c31af7Sopenharmony_ci	const int						maxRenderbufferSize	= queryInt(gl, GL_MAX_RENDERBUFFER_SIZE);
571e5c31af7Sopenharmony_ci	const int						framebufferW		= de::min(maxRenderbufferSize, numValues);
572e5c31af7Sopenharmony_ci	const int						framebufferH		= (numValues / framebufferW) + ((numValues % framebufferW != 0) ? 1 : 0);
573e5c31af7Sopenharmony_ci
574e5c31af7Sopenharmony_ci	glu::Framebuffer				framebuffer			(m_renderCtx);
575e5c31af7Sopenharmony_ci	glu::RenderbufferVector			renderbuffers		(m_renderCtx, m_outputLayout.locationSymbols.size());
576e5c31af7Sopenharmony_ci
577e5c31af7Sopenharmony_ci	vector<glu::VertexArrayBinding>	vertexArrays;
578e5c31af7Sopenharmony_ci	vector<tcu::Vec2>				positions			(numValues);
579e5c31af7Sopenharmony_ci
580e5c31af7Sopenharmony_ci	if (framebufferH > maxRenderbufferSize)
581e5c31af7Sopenharmony_ci		throw tcu::NotSupportedError("Value count is too high for maximum supported renderbuffer size");
582e5c31af7Sopenharmony_ci
583e5c31af7Sopenharmony_ci	// Compute positions - 1px points are used to drive fragment shading.
584e5c31af7Sopenharmony_ci	for (int valNdx = 0; valNdx < numValues; valNdx++)
585e5c31af7Sopenharmony_ci	{
586e5c31af7Sopenharmony_ci		const int		ix		= valNdx % framebufferW;
587e5c31af7Sopenharmony_ci		const int		iy		= valNdx / framebufferW;
588e5c31af7Sopenharmony_ci		const float		fx		= -1.0f + 2.0f*((float(ix) + 0.5f) / float(framebufferW));
589e5c31af7Sopenharmony_ci		const float		fy		= -1.0f + 2.0f*((float(iy) + 0.5f) / float(framebufferH));
590e5c31af7Sopenharmony_ci
591e5c31af7Sopenharmony_ci		positions[valNdx] = tcu::Vec2(fx, fy);
592e5c31af7Sopenharmony_ci	}
593e5c31af7Sopenharmony_ci
594e5c31af7Sopenharmony_ci	// Vertex inputs.
595e5c31af7Sopenharmony_ci	vertexArrays.push_back(glu::va::Float("a_position", 2, numValues, 0, (const float*)&positions[0]));
596e5c31af7Sopenharmony_ci
597e5c31af7Sopenharmony_ci	for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++)
598e5c31af7Sopenharmony_ci	{
599e5c31af7Sopenharmony_ci		const Symbol&		symbol		= m_inputs[inputNdx];
600e5c31af7Sopenharmony_ci		const std::string	attribName	= "a_" + symbol.name;
601e5c31af7Sopenharmony_ci		const void*			ptr			= inputs[inputNdx];
602e5c31af7Sopenharmony_ci		const glu::DataType	basicType	= symbol.varType.getBasicType();
603e5c31af7Sopenharmony_ci		const int			vecSize		= glu::getDataTypeScalarSize(basicType);
604e5c31af7Sopenharmony_ci
605e5c31af7Sopenharmony_ci		if (glu::isDataTypeFloatOrVec(basicType))
606e5c31af7Sopenharmony_ci			vertexArrays.push_back(glu::va::Float(attribName, vecSize, numValues, 0, (const float*)ptr));
607e5c31af7Sopenharmony_ci		else if (glu::isDataTypeIntOrIVec(basicType))
608e5c31af7Sopenharmony_ci			vertexArrays.push_back(glu::va::Int32(attribName, vecSize, numValues, 0, (const deInt32*)ptr));
609e5c31af7Sopenharmony_ci		else if (glu::isDataTypeUintOrUVec(basicType))
610e5c31af7Sopenharmony_ci			vertexArrays.push_back(glu::va::Uint32(attribName, vecSize, numValues, 0, (const deUint32*)ptr));
611e5c31af7Sopenharmony_ci		else if (glu::isDataTypeMatrix(basicType))
612e5c31af7Sopenharmony_ci		{
613e5c31af7Sopenharmony_ci			int		numRows	= glu::getDataTypeMatrixNumRows(basicType);
614e5c31af7Sopenharmony_ci			int		numCols	= glu::getDataTypeMatrixNumColumns(basicType);
615e5c31af7Sopenharmony_ci			int		stride	= numRows * numCols * (int)sizeof(float);
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci			for (int colNdx = 0; colNdx < numCols; ++colNdx)
618e5c31af7Sopenharmony_ci				vertexArrays.push_back(glu::va::Float(attribName, colNdx, numRows, numValues, stride, ((const float*)ptr) + colNdx * numRows));
619e5c31af7Sopenharmony_ci		}
620e5c31af7Sopenharmony_ci		else
621e5c31af7Sopenharmony_ci			DE_ASSERT(false);
622e5c31af7Sopenharmony_ci	}
623e5c31af7Sopenharmony_ci
624e5c31af7Sopenharmony_ci	// Construct framebuffer.
625e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
626e5c31af7Sopenharmony_ci
627e5c31af7Sopenharmony_ci	for (int outNdx = 0; outNdx < (int)m_outputLayout.locationSymbols.size(); ++outNdx)
628e5c31af7Sopenharmony_ci	{
629e5c31af7Sopenharmony_ci		const Symbol&	output			= *m_outputLayout.locationSymbols[outNdx];
630e5c31af7Sopenharmony_ci		const deUint32	renderbuffer	= renderbuffers[outNdx];
631e5c31af7Sopenharmony_ci		const deUint32	format			= glu::getInternalFormat(getRenderbufferFormatForOutput(output.varType, useIntOutputs));
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci		gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
634e5c31af7Sopenharmony_ci		gl.renderbufferStorage(GL_RENDERBUFFER, format, framebufferW, framebufferH);
635e5c31af7Sopenharmony_ci		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+outNdx, GL_RENDERBUFFER, renderbuffer);
636e5c31af7Sopenharmony_ci	}
637e5c31af7Sopenharmony_ci	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
638e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up framebuffer object");
639e5c31af7Sopenharmony_ci	TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
640e5c31af7Sopenharmony_ci
641e5c31af7Sopenharmony_ci	{
642e5c31af7Sopenharmony_ci		vector<deUint32> drawBuffers(m_outputLayout.locationSymbols.size());
643e5c31af7Sopenharmony_ci		for (int ndx = 0; ndx < (int)m_outputLayout.locationSymbols.size(); ndx++)
644e5c31af7Sopenharmony_ci			drawBuffers[ndx] = GL_COLOR_ATTACHMENT0+ndx;
645e5c31af7Sopenharmony_ci		gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]);
646e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffers()");
647e5c31af7Sopenharmony_ci	}
648e5c31af7Sopenharmony_ci
649e5c31af7Sopenharmony_ci	// Render
650e5c31af7Sopenharmony_ci	gl.viewport(0, 0, framebufferW, framebufferH);
651e5c31af7Sopenharmony_ci	glu::draw(m_renderCtx, this->getProgram(), (int)vertexArrays.size(), &vertexArrays[0],
652e5c31af7Sopenharmony_ci			  glu::pr::Points(numValues));
653e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw");
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci	// Read back pixels.
656e5c31af7Sopenharmony_ci	{
657e5c31af7Sopenharmony_ci		tcu::TextureLevel	tmpBuf;
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci		// \todo [2013-08-07 pyry] Some fast-paths could be added here.
660e5c31af7Sopenharmony_ci
661e5c31af7Sopenharmony_ci		for (int outNdx = 0; outNdx < (int)m_outputs.size(); ++outNdx)
662e5c31af7Sopenharmony_ci		{
663e5c31af7Sopenharmony_ci			const Symbol&				output			= m_outputs[outNdx];
664e5c31af7Sopenharmony_ci			const int					outSize			= output.varType.getScalarSize();
665e5c31af7Sopenharmony_ci			const int					outVecSize		= glu::getDataTypeNumComponents(output.varType.getBasicType());
666e5c31af7Sopenharmony_ci			const int					outNumLocs		= glu::getDataTypeNumLocations(output.varType.getBasicType());
667e5c31af7Sopenharmony_ci			deUint32*					dstPtrBase		= static_cast<deUint32*>(outputs[outNdx]);
668e5c31af7Sopenharmony_ci			const tcu::TextureFormat	format			= getRenderbufferFormatForOutput(output.varType, useIntOutputs);
669e5c31af7Sopenharmony_ci			const tcu::TextureFormat	readFormat		(tcu::TextureFormat::RGBA, format.type);
670e5c31af7Sopenharmony_ci			const int					outLocation		= de::lookup(m_outputLayout.locationMap, output.name);
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci			tmpBuf.setStorage(readFormat, framebufferW, framebufferH);
673e5c31af7Sopenharmony_ci
674e5c31af7Sopenharmony_ci			for (int locNdx = 0; locNdx < outNumLocs; ++locNdx)
675e5c31af7Sopenharmony_ci			{
676e5c31af7Sopenharmony_ci				gl.readBuffer(GL_COLOR_ATTACHMENT0 + outLocation + locNdx);
677e5c31af7Sopenharmony_ci				glu::readPixels(m_renderCtx, 0, 0, tmpBuf.getAccess());
678e5c31af7Sopenharmony_ci				GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels");
679e5c31af7Sopenharmony_ci
680e5c31af7Sopenharmony_ci				if (outSize == 4 && outNumLocs == 1)
681e5c31af7Sopenharmony_ci					deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues*outVecSize*sizeof(deUint32));
682e5c31af7Sopenharmony_ci				else
683e5c31af7Sopenharmony_ci				{
684e5c31af7Sopenharmony_ci					for (int valNdx = 0; valNdx < numValues; valNdx++)
685e5c31af7Sopenharmony_ci					{
686e5c31af7Sopenharmony_ci						const deUint32* srcPtr = (const deUint32*)tmpBuf.getAccess().getDataPtr() + valNdx*4;
687e5c31af7Sopenharmony_ci						deUint32*		dstPtr = &dstPtrBase[outSize*valNdx + outVecSize*locNdx];
688e5c31af7Sopenharmony_ci						deMemcpy(dstPtr, srcPtr, outVecSize*sizeof(deUint32));
689e5c31af7Sopenharmony_ci					}
690e5c31af7Sopenharmony_ci				}
691e5c31af7Sopenharmony_ci			}
692e5c31af7Sopenharmony_ci		}
693e5c31af7Sopenharmony_ci	}
694e5c31af7Sopenharmony_ci
695e5c31af7Sopenharmony_ci	// \todo [2013-08-07 pyry] Clear draw buffers & viewport?
696e5c31af7Sopenharmony_ci	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
697e5c31af7Sopenharmony_ci}
698e5c31af7Sopenharmony_ci
699e5c31af7Sopenharmony_ci// VertexShaderExecutor
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ciclass VertexShaderExecutor : public FragmentOutExecutor
702e5c31af7Sopenharmony_ci{
703e5c31af7Sopenharmony_cipublic:
704e5c31af7Sopenharmony_ci								VertexShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
705e5c31af7Sopenharmony_ci								~VertexShaderExecutor	(void);
706e5c31af7Sopenharmony_ci
707e5c31af7Sopenharmony_ci	bool						isOk					(void) const				{ return m_program.isOk();			}
708e5c31af7Sopenharmony_ci	void						log						(tcu::TestLog& dst) const	{ dst << m_program;					}
709e5c31af7Sopenharmony_ci	deUint32					getProgram				(void) const				{ return m_program.getProgram();	}
710e5c31af7Sopenharmony_ci
711e5c31af7Sopenharmony_ciprotected:
712e5c31af7Sopenharmony_ci	const glu::ShaderProgram	m_program;
713e5c31af7Sopenharmony_ci};
714e5c31af7Sopenharmony_ci
715e5c31af7Sopenharmony_ciVertexShaderExecutor::VertexShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
716e5c31af7Sopenharmony_ci	: FragmentOutExecutor	(renderCtx, shaderSpec)
717e5c31af7Sopenharmony_ci	, m_program				(renderCtx,
718e5c31af7Sopenharmony_ci							 glu::ProgramSources() << glu::VertexSource(generateVertexShader(shaderSpec, "a_", "vtx_out_"))
719e5c31af7Sopenharmony_ci												   << glu::FragmentSource(generatePassthroughFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx), m_outputLayout.locationMap, "vtx_out_", "o_")))
720e5c31af7Sopenharmony_ci{
721e5c31af7Sopenharmony_ci}
722e5c31af7Sopenharmony_ci
723e5c31af7Sopenharmony_ciVertexShaderExecutor::~VertexShaderExecutor (void)
724e5c31af7Sopenharmony_ci{
725e5c31af7Sopenharmony_ci}
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_ci// GeometryShaderExecutor
728e5c31af7Sopenharmony_ci
729e5c31af7Sopenharmony_ciclass GeometryShaderExecutor : public FragmentOutExecutor
730e5c31af7Sopenharmony_ci{
731e5c31af7Sopenharmony_cipublic:
732e5c31af7Sopenharmony_ci	static GeometryShaderExecutor*	create					(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
733e5c31af7Sopenharmony_ci
734e5c31af7Sopenharmony_ci									~GeometryShaderExecutor	(void);
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci	bool							isOk					(void) const				{ return m_program.isOk();			}
737e5c31af7Sopenharmony_ci	void							log						(tcu::TestLog& dst) const	{ dst << m_program;					}
738e5c31af7Sopenharmony_ci	deUint32						getProgram				(void) const				{ return m_program.getProgram();	}
739e5c31af7Sopenharmony_ci
740e5c31af7Sopenharmony_ciprotected:
741e5c31af7Sopenharmony_ci	const glu::ShaderProgram		m_program;
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ciprivate:
744e5c31af7Sopenharmony_ci									GeometryShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
745e5c31af7Sopenharmony_ci};
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ciGeometryShaderExecutor* GeometryShaderExecutor::create (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
748e5c31af7Sopenharmony_ci{
749e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES
750e5c31af7Sopenharmony_ci		&& !contextSupports(renderCtx.getType(), glu::ApiType::core(4, 5)))
751e5c31af7Sopenharmony_ci		checkExtension(renderCtx, "GL_EXT_geometry_shader");
752e5c31af7Sopenharmony_ci
753e5c31af7Sopenharmony_ci	return new GeometryShaderExecutor(renderCtx, shaderSpec);
754e5c31af7Sopenharmony_ci}
755e5c31af7Sopenharmony_ci
756e5c31af7Sopenharmony_ciGeometryShaderExecutor::GeometryShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
757e5c31af7Sopenharmony_ci	: FragmentOutExecutor	(renderCtx, shaderSpec)
758e5c31af7Sopenharmony_ci	, m_program				(renderCtx,
759e5c31af7Sopenharmony_ci							 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", "vtx_out_"))
760e5c31af7Sopenharmony_ci												   << glu::GeometrySource(generateGeometryShader(shaderSpec, "vtx_out_", "geom_out_"))
761e5c31af7Sopenharmony_ci												   << glu::FragmentSource(generatePassthroughFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx), m_outputLayout.locationMap, "geom_out_", "o_")))
762e5c31af7Sopenharmony_ci{
763e5c31af7Sopenharmony_ci}
764e5c31af7Sopenharmony_ci
765e5c31af7Sopenharmony_ciGeometryShaderExecutor::~GeometryShaderExecutor (void)
766e5c31af7Sopenharmony_ci{
767e5c31af7Sopenharmony_ci}
768e5c31af7Sopenharmony_ci
769e5c31af7Sopenharmony_ci// FragmentShaderExecutor
770e5c31af7Sopenharmony_ci
771e5c31af7Sopenharmony_ciclass FragmentShaderExecutor : public FragmentOutExecutor
772e5c31af7Sopenharmony_ci{
773e5c31af7Sopenharmony_cipublic:
774e5c31af7Sopenharmony_ci								FragmentShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
775e5c31af7Sopenharmony_ci								~FragmentShaderExecutor	(void);
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_ci	bool						isOk					(void) const				{ return m_program.isOk();			}
778e5c31af7Sopenharmony_ci	void						log						(tcu::TestLog& dst) const	{ dst << m_program;					}
779e5c31af7Sopenharmony_ci	deUint32					getProgram				(void) const				{ return m_program.getProgram();	}
780e5c31af7Sopenharmony_ci
781e5c31af7Sopenharmony_ciprotected:
782e5c31af7Sopenharmony_ci	const glu::ShaderProgram	m_program;
783e5c31af7Sopenharmony_ci};
784e5c31af7Sopenharmony_ci
785e5c31af7Sopenharmony_ciFragmentShaderExecutor::FragmentShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
786e5c31af7Sopenharmony_ci	: FragmentOutExecutor	(renderCtx, shaderSpec)
787e5c31af7Sopenharmony_ci	, m_program				(renderCtx,
788e5c31af7Sopenharmony_ci							 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", "vtx_out_"))
789e5c31af7Sopenharmony_ci												   << glu::FragmentSource(generateFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx), m_outputLayout.locationMap, "vtx_out_", "o_")))
790e5c31af7Sopenharmony_ci{
791e5c31af7Sopenharmony_ci}
792e5c31af7Sopenharmony_ci
793e5c31af7Sopenharmony_ciFragmentShaderExecutor::~FragmentShaderExecutor (void)
794e5c31af7Sopenharmony_ci{
795e5c31af7Sopenharmony_ci}
796e5c31af7Sopenharmony_ci
797e5c31af7Sopenharmony_ci// Shared utilities for compute and tess executors
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_cistatic deUint32 getVecStd430ByteAlignment (glu::DataType type)
800e5c31af7Sopenharmony_ci{
801e5c31af7Sopenharmony_ci	switch (glu::getDataTypeScalarSize(type))
802e5c31af7Sopenharmony_ci	{
803e5c31af7Sopenharmony_ci		case 1:		return 4u;
804e5c31af7Sopenharmony_ci		case 2:		return 8u;
805e5c31af7Sopenharmony_ci		case 3:		return 16u;
806e5c31af7Sopenharmony_ci		case 4:		return 16u;
807e5c31af7Sopenharmony_ci		default:
808e5c31af7Sopenharmony_ci			DE_ASSERT(false);
809e5c31af7Sopenharmony_ci			return 0u;
810e5c31af7Sopenharmony_ci	}
811e5c31af7Sopenharmony_ci}
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ciclass BufferIoExecutor : public ShaderExecutor
814e5c31af7Sopenharmony_ci{
815e5c31af7Sopenharmony_cipublic:
816e5c31af7Sopenharmony_ci						BufferIoExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources);
817e5c31af7Sopenharmony_ci						~BufferIoExecutor	(void);
818e5c31af7Sopenharmony_ci
819e5c31af7Sopenharmony_ci	bool				isOk				(void) const				{ return m_program.isOk();			}
820e5c31af7Sopenharmony_ci	void				log					(tcu::TestLog& dst) const	{ dst << m_program;					}
821e5c31af7Sopenharmony_ci	deUint32			getProgram			(void) const				{ return m_program.getProgram();	}
822e5c31af7Sopenharmony_ci
823e5c31af7Sopenharmony_ciprotected:
824e5c31af7Sopenharmony_ci	enum
825e5c31af7Sopenharmony_ci	{
826e5c31af7Sopenharmony_ci		INPUT_BUFFER_BINDING	= 0,
827e5c31af7Sopenharmony_ci		OUTPUT_BUFFER_BINDING	= 1,
828e5c31af7Sopenharmony_ci	};
829e5c31af7Sopenharmony_ci
830e5c31af7Sopenharmony_ci	void				initBuffers			(int numValues);
831e5c31af7Sopenharmony_ci	deUint32			getInputBuffer		(void) const		{ return *m_inputBuffer;					}
832e5c31af7Sopenharmony_ci	deUint32			getOutputBuffer		(void) const		{ return *m_outputBuffer;					}
833e5c31af7Sopenharmony_ci	deUint32			getInputStride		(void) const		{ return getLayoutStride(m_inputLayout);	}
834e5c31af7Sopenharmony_ci	deUint32			getOutputStride		(void) const		{ return getLayoutStride(m_outputLayout);	}
835e5c31af7Sopenharmony_ci
836e5c31af7Sopenharmony_ci	void				uploadInputBuffer	(const void* const* inputPtrs, int numValues);
837e5c31af7Sopenharmony_ci	void				readOutputBuffer	(void* const* outputPtrs, int numValues);
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_ci	static void			declareBufferBlocks	(std::ostream& src, const ShaderSpec& spec);
840e5c31af7Sopenharmony_ci	static void			generateExecBufferIo(std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName);
841e5c31af7Sopenharmony_ci
842e5c31af7Sopenharmony_ci	glu::ShaderProgram	m_program;
843e5c31af7Sopenharmony_ci
844e5c31af7Sopenharmony_ciprivate:
845e5c31af7Sopenharmony_ci	struct VarLayout
846e5c31af7Sopenharmony_ci	{
847e5c31af7Sopenharmony_ci		deUint32		offset;
848e5c31af7Sopenharmony_ci		deUint32		stride;
849e5c31af7Sopenharmony_ci		deUint32		matrixStride;
850e5c31af7Sopenharmony_ci
851e5c31af7Sopenharmony_ci		VarLayout (void) : offset(0), stride(0), matrixStride(0) {}
852e5c31af7Sopenharmony_ci	};
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci	void				resizeInputBuffer	(int newSize);
855e5c31af7Sopenharmony_ci	void				resizeOutputBuffer	(int newSize);
856e5c31af7Sopenharmony_ci
857e5c31af7Sopenharmony_ci	static void			computeVarLayout	(const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout);
858e5c31af7Sopenharmony_ci	static deUint32		getLayoutStride		(const vector<VarLayout>& layout);
859e5c31af7Sopenharmony_ci
860e5c31af7Sopenharmony_ci	static void			copyToBuffer		(const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
861e5c31af7Sopenharmony_ci	static void			copyFromBuffer		(const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
862e5c31af7Sopenharmony_ci
863e5c31af7Sopenharmony_ci	glu::Buffer			m_inputBuffer;
864e5c31af7Sopenharmony_ci	glu::Buffer			m_outputBuffer;
865e5c31af7Sopenharmony_ci
866e5c31af7Sopenharmony_ci	vector<VarLayout>	m_inputLayout;
867e5c31af7Sopenharmony_ci	vector<VarLayout>	m_outputLayout;
868e5c31af7Sopenharmony_ci};
869e5c31af7Sopenharmony_ci
870e5c31af7Sopenharmony_ciBufferIoExecutor::BufferIoExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources)
871e5c31af7Sopenharmony_ci	: ShaderExecutor	(renderCtx, shaderSpec)
872e5c31af7Sopenharmony_ci	, m_program			(renderCtx, sources)
873e5c31af7Sopenharmony_ci	, m_inputBuffer		(renderCtx)
874e5c31af7Sopenharmony_ci	, m_outputBuffer	(renderCtx)
875e5c31af7Sopenharmony_ci{
876e5c31af7Sopenharmony_ci	computeVarLayout(m_inputs, &m_inputLayout);
877e5c31af7Sopenharmony_ci	computeVarLayout(m_outputs, &m_outputLayout);
878e5c31af7Sopenharmony_ci}
879e5c31af7Sopenharmony_ci
880e5c31af7Sopenharmony_ciBufferIoExecutor::~BufferIoExecutor (void)
881e5c31af7Sopenharmony_ci{
882e5c31af7Sopenharmony_ci}
883e5c31af7Sopenharmony_ci
884e5c31af7Sopenharmony_civoid BufferIoExecutor::resizeInputBuffer (int newSize)
885e5c31af7Sopenharmony_ci{
886e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_renderCtx.getFunctions();
887e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_inputBuffer);
888e5c31af7Sopenharmony_ci	gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
889e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate input buffer");
890e5c31af7Sopenharmony_ci}
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_civoid BufferIoExecutor::resizeOutputBuffer (int newSize)
893e5c31af7Sopenharmony_ci{
894e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_renderCtx.getFunctions();
895e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_outputBuffer);
896e5c31af7Sopenharmony_ci	gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
897e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate output buffer");
898e5c31af7Sopenharmony_ci}
899e5c31af7Sopenharmony_ci
900e5c31af7Sopenharmony_civoid BufferIoExecutor::initBuffers (int numValues)
901e5c31af7Sopenharmony_ci{
902e5c31af7Sopenharmony_ci	const deUint32		inputStride			= getLayoutStride(m_inputLayout);
903e5c31af7Sopenharmony_ci	const deUint32		outputStride		= getLayoutStride(m_outputLayout);
904e5c31af7Sopenharmony_ci	const int			inputBufferSize		= numValues * inputStride;
905e5c31af7Sopenharmony_ci	const int			outputBufferSize	= numValues * outputStride;
906e5c31af7Sopenharmony_ci
907e5c31af7Sopenharmony_ci	resizeInputBuffer(inputBufferSize);
908e5c31af7Sopenharmony_ci	resizeOutputBuffer(outputBufferSize);
909e5c31af7Sopenharmony_ci}
910e5c31af7Sopenharmony_ci
911e5c31af7Sopenharmony_civoid BufferIoExecutor::computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout)
912e5c31af7Sopenharmony_ci{
913e5c31af7Sopenharmony_ci	deUint32	maxAlignment	= 0;
914e5c31af7Sopenharmony_ci	deUint32	curOffset		= 0;
915e5c31af7Sopenharmony_ci
916e5c31af7Sopenharmony_ci	DE_ASSERT(layout->empty());
917e5c31af7Sopenharmony_ci	layout->resize(symbols.size());
918e5c31af7Sopenharmony_ci
919e5c31af7Sopenharmony_ci	for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++)
920e5c31af7Sopenharmony_ci	{
921e5c31af7Sopenharmony_ci		const Symbol&		symbol		= symbols[varNdx];
922e5c31af7Sopenharmony_ci		const glu::DataType	basicType	= symbol.varType.getBasicType();
923e5c31af7Sopenharmony_ci		VarLayout&			layoutEntry	= (*layout)[varNdx];
924e5c31af7Sopenharmony_ci
925e5c31af7Sopenharmony_ci		if (glu::isDataTypeScalarOrVector(basicType))
926e5c31af7Sopenharmony_ci		{
927e5c31af7Sopenharmony_ci			const deUint32	alignment	= getVecStd430ByteAlignment(basicType);
928e5c31af7Sopenharmony_ci			const deUint32	size		= (deUint32)glu::getDataTypeScalarSize(basicType)*(int)sizeof(deUint32);
929e5c31af7Sopenharmony_ci
930e5c31af7Sopenharmony_ci			curOffset		= (deUint32)deAlign32((int)curOffset, (int)alignment);
931e5c31af7Sopenharmony_ci			maxAlignment	= de::max(maxAlignment, alignment);
932e5c31af7Sopenharmony_ci
933e5c31af7Sopenharmony_ci			layoutEntry.offset			= curOffset;
934e5c31af7Sopenharmony_ci			layoutEntry.matrixStride	= 0;
935e5c31af7Sopenharmony_ci
936e5c31af7Sopenharmony_ci			curOffset += size;
937e5c31af7Sopenharmony_ci		}
938e5c31af7Sopenharmony_ci		else if (glu::isDataTypeMatrix(basicType))
939e5c31af7Sopenharmony_ci		{
940e5c31af7Sopenharmony_ci			const int				numVecs			= glu::getDataTypeMatrixNumColumns(basicType);
941e5c31af7Sopenharmony_ci			const glu::DataType		vecType			= glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType));
942e5c31af7Sopenharmony_ci			const deUint32			vecAlignment	= getVecStd430ByteAlignment(vecType);
943e5c31af7Sopenharmony_ci
944e5c31af7Sopenharmony_ci			curOffset		= (deUint32)deAlign32((int)curOffset, (int)vecAlignment);
945e5c31af7Sopenharmony_ci			maxAlignment	= de::max(maxAlignment, vecAlignment);
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci			layoutEntry.offset			= curOffset;
948e5c31af7Sopenharmony_ci			layoutEntry.matrixStride	= vecAlignment;
949e5c31af7Sopenharmony_ci
950e5c31af7Sopenharmony_ci			curOffset += vecAlignment*numVecs;
951e5c31af7Sopenharmony_ci		}
952e5c31af7Sopenharmony_ci		else
953e5c31af7Sopenharmony_ci			DE_ASSERT(false);
954e5c31af7Sopenharmony_ci	}
955e5c31af7Sopenharmony_ci
956e5c31af7Sopenharmony_ci	{
957e5c31af7Sopenharmony_ci		const deUint32	totalSize	= (deUint32)deAlign32(curOffset, maxAlignment);
958e5c31af7Sopenharmony_ci
959e5c31af7Sopenharmony_ci		for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter)
960e5c31af7Sopenharmony_ci			varIter->stride = totalSize;
961e5c31af7Sopenharmony_ci	}
962e5c31af7Sopenharmony_ci}
963e5c31af7Sopenharmony_ci
964e5c31af7Sopenharmony_ciinline deUint32 BufferIoExecutor::getLayoutStride (const vector<VarLayout>& layout)
965e5c31af7Sopenharmony_ci{
966e5c31af7Sopenharmony_ci	return layout.empty() ? 0 : layout[0].stride;
967e5c31af7Sopenharmony_ci}
968e5c31af7Sopenharmony_ci
969e5c31af7Sopenharmony_civoid BufferIoExecutor::copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
970e5c31af7Sopenharmony_ci{
971e5c31af7Sopenharmony_ci	if (varType.isBasicType())
972e5c31af7Sopenharmony_ci	{
973e5c31af7Sopenharmony_ci		const glu::DataType		basicType		= varType.getBasicType();
974e5c31af7Sopenharmony_ci		const bool				isMatrix		= glu::isDataTypeMatrix(basicType);
975e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
976e5c31af7Sopenharmony_ci		const int				numVecs			= isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
977e5c31af7Sopenharmony_ci		const int				numComps		= scalarSize / numVecs;
978e5c31af7Sopenharmony_ci
979e5c31af7Sopenharmony_ci		for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
980e5c31af7Sopenharmony_ci		{
981e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
982e5c31af7Sopenharmony_ci			{
983e5c31af7Sopenharmony_ci				const int		srcOffset		= (int)sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps);
984e5c31af7Sopenharmony_ci				const int		dstOffset		= layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0);
985e5c31af7Sopenharmony_ci				const deUint8*	srcPtr			= (const deUint8*)srcBasePtr + srcOffset;
986e5c31af7Sopenharmony_ci				deUint8*		dstPtr			= (deUint8*)dstBasePtr + dstOffset;
987e5c31af7Sopenharmony_ci
988e5c31af7Sopenharmony_ci				deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps);
989e5c31af7Sopenharmony_ci			}
990e5c31af7Sopenharmony_ci		}
991e5c31af7Sopenharmony_ci	}
992e5c31af7Sopenharmony_ci	else
993e5c31af7Sopenharmony_ci		throw tcu::InternalError("Unsupported type");
994e5c31af7Sopenharmony_ci}
995e5c31af7Sopenharmony_ci
996e5c31af7Sopenharmony_civoid BufferIoExecutor::copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
997e5c31af7Sopenharmony_ci{
998e5c31af7Sopenharmony_ci	if (varType.isBasicType())
999e5c31af7Sopenharmony_ci	{
1000e5c31af7Sopenharmony_ci		const glu::DataType		basicType		= varType.getBasicType();
1001e5c31af7Sopenharmony_ci		const bool				isMatrix		= glu::isDataTypeMatrix(basicType);
1002e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
1003e5c31af7Sopenharmony_ci		const int				numVecs			= isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
1004e5c31af7Sopenharmony_ci		const int				numComps		= scalarSize / numVecs;
1005e5c31af7Sopenharmony_ci
1006e5c31af7Sopenharmony_ci		for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
1007e5c31af7Sopenharmony_ci		{
1008e5c31af7Sopenharmony_ci			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1009e5c31af7Sopenharmony_ci			{
1010e5c31af7Sopenharmony_ci				const int		srcOffset		= layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0);
1011e5c31af7Sopenharmony_ci				const int		dstOffset		= (int)sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps);
1012e5c31af7Sopenharmony_ci				const deUint8*	srcPtr			= (const deUint8*)srcBasePtr + srcOffset;
1013e5c31af7Sopenharmony_ci				deUint8*		dstPtr			= (deUint8*)dstBasePtr + dstOffset;
1014e5c31af7Sopenharmony_ci
1015e5c31af7Sopenharmony_ci				deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps);
1016e5c31af7Sopenharmony_ci			}
1017e5c31af7Sopenharmony_ci		}
1018e5c31af7Sopenharmony_ci	}
1019e5c31af7Sopenharmony_ci	else
1020e5c31af7Sopenharmony_ci		throw tcu::InternalError("Unsupported type");
1021e5c31af7Sopenharmony_ci}
1022e5c31af7Sopenharmony_ci
1023e5c31af7Sopenharmony_civoid BufferIoExecutor::uploadInputBuffer (const void* const* inputPtrs, int numValues)
1024e5c31af7Sopenharmony_ci{
1025e5c31af7Sopenharmony_ci	const glw::Functions&	gl				= m_renderCtx.getFunctions();
1026e5c31af7Sopenharmony_ci	const deUint32			buffer			= *m_inputBuffer;
1027e5c31af7Sopenharmony_ci	const deUint32			inputStride		= getLayoutStride(m_inputLayout);
1028e5c31af7Sopenharmony_ci	const int				inputBufferSize	= inputStride*numValues;
1029e5c31af7Sopenharmony_ci
1030e5c31af7Sopenharmony_ci	if (inputBufferSize == 0)
1031e5c31af7Sopenharmony_ci		return; // No inputs
1032e5c31af7Sopenharmony_ci
1033e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
1034e5c31af7Sopenharmony_ci	void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, inputBufferSize, GL_MAP_WRITE_BIT);
1035e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1036e5c31af7Sopenharmony_ci	TCU_CHECK(mapPtr);
1037e5c31af7Sopenharmony_ci
1038e5c31af7Sopenharmony_ci	try
1039e5c31af7Sopenharmony_ci	{
1040e5c31af7Sopenharmony_ci		DE_ASSERT(m_inputs.size() == m_inputLayout.size());
1041e5c31af7Sopenharmony_ci		for (size_t inputNdx = 0; inputNdx < m_inputs.size(); ++inputNdx)
1042e5c31af7Sopenharmony_ci		{
1043e5c31af7Sopenharmony_ci			const glu::VarType&		varType		= m_inputs[inputNdx].varType;
1044e5c31af7Sopenharmony_ci			const VarLayout&		layout		= m_inputLayout[inputNdx];
1045e5c31af7Sopenharmony_ci
1046e5c31af7Sopenharmony_ci			copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], mapPtr);
1047e5c31af7Sopenharmony_ci		}
1048e5c31af7Sopenharmony_ci	}
1049e5c31af7Sopenharmony_ci	catch (...)
1050e5c31af7Sopenharmony_ci	{
1051e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1052e5c31af7Sopenharmony_ci		throw;
1053e5c31af7Sopenharmony_ci	}
1054e5c31af7Sopenharmony_ci
1055e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1056e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1057e5c31af7Sopenharmony_ci}
1058e5c31af7Sopenharmony_ci
1059e5c31af7Sopenharmony_civoid BufferIoExecutor::readOutputBuffer (void* const* outputPtrs, int numValues)
1060e5c31af7Sopenharmony_ci{
1061e5c31af7Sopenharmony_ci	const glw::Functions&	gl					= m_renderCtx.getFunctions();
1062e5c31af7Sopenharmony_ci	const deUint32			buffer				= *m_outputBuffer;
1063e5c31af7Sopenharmony_ci	const deUint32			outputStride		= getLayoutStride(m_outputLayout);
1064e5c31af7Sopenharmony_ci	const int				outputBufferSize	= numValues*outputStride;
1065e5c31af7Sopenharmony_ci
1066e5c31af7Sopenharmony_ci	DE_ASSERT(outputBufferSize > 0); // At least some outputs are required.
1067e5c31af7Sopenharmony_ci
1068e5c31af7Sopenharmony_ci	gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1069e5c31af7Sopenharmony_ci	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
1070e5c31af7Sopenharmony_ci	void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, outputBufferSize, GL_MAP_READ_BIT);
1071e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1072e5c31af7Sopenharmony_ci	TCU_CHECK(mapPtr);
1073e5c31af7Sopenharmony_ci
1074e5c31af7Sopenharmony_ci	try
1075e5c31af7Sopenharmony_ci	{
1076e5c31af7Sopenharmony_ci		DE_ASSERT(m_outputs.size() == m_outputLayout.size());
1077e5c31af7Sopenharmony_ci		for (size_t outputNdx = 0; outputNdx < m_outputs.size(); ++outputNdx)
1078e5c31af7Sopenharmony_ci		{
1079e5c31af7Sopenharmony_ci			const glu::VarType&		varType		= m_outputs[outputNdx].varType;
1080e5c31af7Sopenharmony_ci			const VarLayout&		layout		= m_outputLayout[outputNdx];
1081e5c31af7Sopenharmony_ci
1082e5c31af7Sopenharmony_ci			copyFromBuffer(varType, layout, numValues, mapPtr, outputPtrs[outputNdx]);
1083e5c31af7Sopenharmony_ci		}
1084e5c31af7Sopenharmony_ci	}
1085e5c31af7Sopenharmony_ci	catch (...)
1086e5c31af7Sopenharmony_ci	{
1087e5c31af7Sopenharmony_ci		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1088e5c31af7Sopenharmony_ci		throw;
1089e5c31af7Sopenharmony_ci	}
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1092e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1093e5c31af7Sopenharmony_ci}
1094e5c31af7Sopenharmony_ci
1095e5c31af7Sopenharmony_civoid BufferIoExecutor::declareBufferBlocks (std::ostream& src, const ShaderSpec& spec)
1096e5c31af7Sopenharmony_ci{
1097e5c31af7Sopenharmony_ci	// Input struct
1098e5c31af7Sopenharmony_ci	if (!spec.inputs.empty())
1099e5c31af7Sopenharmony_ci	{
1100e5c31af7Sopenharmony_ci		glu::StructType inputStruct("Inputs");
1101e5c31af7Sopenharmony_ci		for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
1102e5c31af7Sopenharmony_ci			inputStruct.addMember(symIter->name.c_str(), symIter->varType);
1103e5c31af7Sopenharmony_ci		src << glu::declare(&inputStruct) << ";\n";
1104e5c31af7Sopenharmony_ci	}
1105e5c31af7Sopenharmony_ci
1106e5c31af7Sopenharmony_ci	// Output struct
1107e5c31af7Sopenharmony_ci	{
1108e5c31af7Sopenharmony_ci		glu::StructType outputStruct("Outputs");
1109e5c31af7Sopenharmony_ci		for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1110e5c31af7Sopenharmony_ci			outputStruct.addMember(symIter->name.c_str(), symIter->varType);
1111e5c31af7Sopenharmony_ci		src << glu::declare(&outputStruct) << ";\n";
1112e5c31af7Sopenharmony_ci	}
1113e5c31af7Sopenharmony_ci
1114e5c31af7Sopenharmony_ci	src << "\n";
1115e5c31af7Sopenharmony_ci
1116e5c31af7Sopenharmony_ci	if (!spec.inputs.empty())
1117e5c31af7Sopenharmony_ci	{
1118e5c31af7Sopenharmony_ci		src	<< "layout(binding = " << int(INPUT_BUFFER_BINDING) << ", std430) buffer InBuffer\n"
1119e5c31af7Sopenharmony_ci			<< "{\n"
1120e5c31af7Sopenharmony_ci			<< "	Inputs inputs[];\n"
1121e5c31af7Sopenharmony_ci			<< "};\n";
1122e5c31af7Sopenharmony_ci	}
1123e5c31af7Sopenharmony_ci
1124e5c31af7Sopenharmony_ci	src	<< "layout(binding = " << int(OUTPUT_BUFFER_BINDING) << ", std430) buffer OutBuffer\n"
1125e5c31af7Sopenharmony_ci		<< "{\n"
1126e5c31af7Sopenharmony_ci		<< "	Outputs outputs[];\n"
1127e5c31af7Sopenharmony_ci		<< "};\n"
1128e5c31af7Sopenharmony_ci		<< "\n";
1129e5c31af7Sopenharmony_ci}
1130e5c31af7Sopenharmony_ci
1131e5c31af7Sopenharmony_civoid BufferIoExecutor::generateExecBufferIo (std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName)
1132e5c31af7Sopenharmony_ci{
1133e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
1134e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]." << symIter->name << ";\n";
1135e5c31af7Sopenharmony_ci
1136e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1137e5c31af7Sopenharmony_ci		src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n";
1138e5c31af7Sopenharmony_ci
1139e5c31af7Sopenharmony_ci	src << "\n";
1140e5c31af7Sopenharmony_ci
1141e5c31af7Sopenharmony_ci	{
1142e5c31af7Sopenharmony_ci		std::istringstream	opSrc	(spec.source);
1143e5c31af7Sopenharmony_ci		std::string			line;
1144e5c31af7Sopenharmony_ci
1145e5c31af7Sopenharmony_ci		while (std::getline(opSrc, line))
1146e5c31af7Sopenharmony_ci			src << "\t" << line << "\n";
1147e5c31af7Sopenharmony_ci	}
1148e5c31af7Sopenharmony_ci
1149e5c31af7Sopenharmony_ci	src << "\n";
1150e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1151e5c31af7Sopenharmony_ci		src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n";
1152e5c31af7Sopenharmony_ci}
1153e5c31af7Sopenharmony_ci
1154e5c31af7Sopenharmony_ci// ComputeShaderExecutor
1155e5c31af7Sopenharmony_ci
1156e5c31af7Sopenharmony_ciclass ComputeShaderExecutor : public BufferIoExecutor
1157e5c31af7Sopenharmony_ci{
1158e5c31af7Sopenharmony_cipublic:
1159e5c31af7Sopenharmony_ci						ComputeShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
1160e5c31af7Sopenharmony_ci						~ComputeShaderExecutor	(void);
1161e5c31af7Sopenharmony_ci
1162e5c31af7Sopenharmony_ci	void				execute					(int numValues, const void* const* inputs, void* const* outputs);
1163e5c31af7Sopenharmony_ci
1164e5c31af7Sopenharmony_ciprotected:
1165e5c31af7Sopenharmony_ci	static std::string	generateComputeShader	(const ShaderSpec& spec);
1166e5c31af7Sopenharmony_ci
1167e5c31af7Sopenharmony_ci	tcu::IVec3			m_maxWorkSize;
1168e5c31af7Sopenharmony_ci};
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_cistd::string ComputeShaderExecutor::generateComputeShader (const ShaderSpec& spec)
1171e5c31af7Sopenharmony_ci{
1172e5c31af7Sopenharmony_ci	std::ostringstream src;
1173e5c31af7Sopenharmony_ci
1174e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(spec.version) << "\n";
1175e5c31af7Sopenharmony_ci
1176e5c31af7Sopenharmony_ci	if (!spec.globalDeclarations.empty())
1177e5c31af7Sopenharmony_ci		src << spec.globalDeclarations << "\n";
1178e5c31af7Sopenharmony_ci
1179e5c31af7Sopenharmony_ci	src << "layout(local_size_x = 1) in;\n"
1180e5c31af7Sopenharmony_ci		<< "\n";
1181e5c31af7Sopenharmony_ci
1182e5c31af7Sopenharmony_ci	declareBufferBlocks(src, spec);
1183e5c31af7Sopenharmony_ci
1184e5c31af7Sopenharmony_ci	src << "void main (void)\n"
1185e5c31af7Sopenharmony_ci		<< "{\n"
1186e5c31af7Sopenharmony_ci		<< "	uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n"
1187e5c31af7Sopenharmony_ci		<< "	                   + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n";
1188e5c31af7Sopenharmony_ci
1189e5c31af7Sopenharmony_ci	generateExecBufferIo(src, spec, "invocationNdx");
1190e5c31af7Sopenharmony_ci
1191e5c31af7Sopenharmony_ci	src << "}\n";
1192e5c31af7Sopenharmony_ci
1193e5c31af7Sopenharmony_ci	return src.str();
1194e5c31af7Sopenharmony_ci}
1195e5c31af7Sopenharmony_ci
1196e5c31af7Sopenharmony_ciComputeShaderExecutor::ComputeShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1197e5c31af7Sopenharmony_ci	: BufferIoExecutor	(renderCtx, shaderSpec,
1198e5c31af7Sopenharmony_ci						 glu::ProgramSources() << glu::ComputeSource(generateComputeShader(shaderSpec)))
1199e5c31af7Sopenharmony_ci{
1200e5c31af7Sopenharmony_ci	m_maxWorkSize	= tcu::IVec3(128,128,64); // Minimum in 3plus
1201e5c31af7Sopenharmony_ci}
1202e5c31af7Sopenharmony_ci
1203e5c31af7Sopenharmony_ciComputeShaderExecutor::~ComputeShaderExecutor (void)
1204e5c31af7Sopenharmony_ci{
1205e5c31af7Sopenharmony_ci}
1206e5c31af7Sopenharmony_ci
1207e5c31af7Sopenharmony_civoid ComputeShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
1208e5c31af7Sopenharmony_ci{
1209e5c31af7Sopenharmony_ci	const glw::Functions&	gl						= m_renderCtx.getFunctions();
1210e5c31af7Sopenharmony_ci	const int				maxValuesPerInvocation	= m_maxWorkSize[0];
1211e5c31af7Sopenharmony_ci	const deUint32			inputStride				= getInputStride();
1212e5c31af7Sopenharmony_ci	const deUint32			outputStride			= getOutputStride();
1213e5c31af7Sopenharmony_ci
1214e5c31af7Sopenharmony_ci	initBuffers(numValues);
1215e5c31af7Sopenharmony_ci
1216e5c31af7Sopenharmony_ci	// Setup input buffer & copy data
1217e5c31af7Sopenharmony_ci	uploadInputBuffer(inputs, numValues);
1218e5c31af7Sopenharmony_ci
1219e5c31af7Sopenharmony_ci	// Perform compute invocations
1220e5c31af7Sopenharmony_ci	{
1221e5c31af7Sopenharmony_ci		int curOffset = 0;
1222e5c31af7Sopenharmony_ci		while (curOffset < numValues)
1223e5c31af7Sopenharmony_ci		{
1224e5c31af7Sopenharmony_ci			const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset);
1225e5c31af7Sopenharmony_ci
1226e5c31af7Sopenharmony_ci			if (inputStride > 0)
1227e5c31af7Sopenharmony_ci				gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer(), curOffset*inputStride, numToExec*inputStride);
1228e5c31af7Sopenharmony_ci
1229e5c31af7Sopenharmony_ci			gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer(), curOffset*outputStride, numToExec*outputStride);
1230e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_SHADER_STORAGE_BUFFER)");
1231e5c31af7Sopenharmony_ci
1232e5c31af7Sopenharmony_ci			gl.dispatchCompute(numToExec, 1, 1);
1233e5c31af7Sopenharmony_ci			GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()");
1234e5c31af7Sopenharmony_ci
1235e5c31af7Sopenharmony_ci			curOffset += numToExec;
1236e5c31af7Sopenharmony_ci		}
1237e5c31af7Sopenharmony_ci	}
1238e5c31af7Sopenharmony_ci
1239e5c31af7Sopenharmony_ci	// Read back data
1240e5c31af7Sopenharmony_ci	readOutputBuffer(outputs, numValues);
1241e5c31af7Sopenharmony_ci}
1242e5c31af7Sopenharmony_ci
1243e5c31af7Sopenharmony_ci// Tessellation utils
1244e5c31af7Sopenharmony_ci
1245e5c31af7Sopenharmony_cistatic std::string generateVertexShaderForTess (glu::GLSLVersion version)
1246e5c31af7Sopenharmony_ci{
1247e5c31af7Sopenharmony_ci	std::ostringstream	src;
1248e5c31af7Sopenharmony_ci
1249e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(version) << "\n";
1250e5c31af7Sopenharmony_ci
1251e5c31af7Sopenharmony_ci	src << "void main (void)\n{\n"
1252e5c31af7Sopenharmony_ci		<< "	gl_Position = vec4(gl_VertexID/2, gl_VertexID%2, 0.0, 1.0);\n"
1253e5c31af7Sopenharmony_ci		<< "}\n";
1254e5c31af7Sopenharmony_ci
1255e5c31af7Sopenharmony_ci	return src.str();
1256e5c31af7Sopenharmony_ci}
1257e5c31af7Sopenharmony_ci
1258e5c31af7Sopenharmony_civoid checkTessSupport (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, glu::ShaderType stage)
1259e5c31af7Sopenharmony_ci{
1260e5c31af7Sopenharmony_ci	const int numBlockRequired = 2; // highest binding is always 1 (output) i.e. count == 2
1261e5c31af7Sopenharmony_ci
1262e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES
1263e5c31af7Sopenharmony_ci		&& !contextSupports(renderCtx.getType(), glu::ApiType::core(4, 5)))
1264e5c31af7Sopenharmony_ci		checkExtension(renderCtx, "GL_EXT_tessellation_shader");
1265e5c31af7Sopenharmony_ci
1266e5c31af7Sopenharmony_ci	if (stage == glu::SHADERTYPE_TESSELLATION_CONTROL)
1267e5c31af7Sopenharmony_ci		checkLimit(renderCtx, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, numBlockRequired);
1268e5c31af7Sopenharmony_ci	else if (stage == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1269e5c31af7Sopenharmony_ci		checkLimit(renderCtx, GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, numBlockRequired);
1270e5c31af7Sopenharmony_ci	else
1271e5c31af7Sopenharmony_ci		DE_ASSERT(false);
1272e5c31af7Sopenharmony_ci}
1273e5c31af7Sopenharmony_ci
1274e5c31af7Sopenharmony_ci// TessControlExecutor
1275e5c31af7Sopenharmony_ci
1276e5c31af7Sopenharmony_ciclass TessControlExecutor : public BufferIoExecutor
1277e5c31af7Sopenharmony_ci{
1278e5c31af7Sopenharmony_cipublic:
1279e5c31af7Sopenharmony_ci	static TessControlExecutor*	create						(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
1280e5c31af7Sopenharmony_ci
1281e5c31af7Sopenharmony_ci								~TessControlExecutor		(void);
1282e5c31af7Sopenharmony_ci
1283e5c31af7Sopenharmony_ci	void						execute						(int numValues, const void* const* inputs, void* const* outputs);
1284e5c31af7Sopenharmony_ci
1285e5c31af7Sopenharmony_ci
1286e5c31af7Sopenharmony_ciprotected:
1287e5c31af7Sopenharmony_ci	static std::string			generateTessControlShader	(const ShaderSpec& shaderSpec);
1288e5c31af7Sopenharmony_ci
1289e5c31af7Sopenharmony_ciprivate:
1290e5c31af7Sopenharmony_ci								TessControlExecutor			(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
1291e5c31af7Sopenharmony_ci};
1292e5c31af7Sopenharmony_ci
1293e5c31af7Sopenharmony_ciTessControlExecutor* TessControlExecutor::create (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1294e5c31af7Sopenharmony_ci{
1295e5c31af7Sopenharmony_ci	checkTessSupport(renderCtx, shaderSpec, glu::SHADERTYPE_TESSELLATION_CONTROL);
1296e5c31af7Sopenharmony_ci
1297e5c31af7Sopenharmony_ci	return new TessControlExecutor(renderCtx, shaderSpec);
1298e5c31af7Sopenharmony_ci}
1299e5c31af7Sopenharmony_ci
1300e5c31af7Sopenharmony_cistd::string TessControlExecutor::generateTessControlShader (const ShaderSpec& shaderSpec)
1301e5c31af7Sopenharmony_ci{
1302e5c31af7Sopenharmony_ci	std::ostringstream src;
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1305e5c31af7Sopenharmony_ci
1306e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
1307e5c31af7Sopenharmony_ci		src << "#extension GL_EXT_tessellation_shader : require\n";
1308e5c31af7Sopenharmony_ci
1309e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
1310e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
1311e5c31af7Sopenharmony_ci
1312e5c31af7Sopenharmony_ci	src << "\nlayout(vertices = 1) out;\n\n";
1313e5c31af7Sopenharmony_ci
1314e5c31af7Sopenharmony_ci	declareBufferBlocks(src, shaderSpec);
1315e5c31af7Sopenharmony_ci
1316e5c31af7Sopenharmony_ci	src << "void main (void)\n{\n";
1317e5c31af7Sopenharmony_ci
1318e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < 2; ndx++)
1319e5c31af7Sopenharmony_ci		src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
1320e5c31af7Sopenharmony_ci
1321e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < 4; ndx++)
1322e5c31af7Sopenharmony_ci		src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
1323e5c31af7Sopenharmony_ci
1324e5c31af7Sopenharmony_ci	src << "\n"
1325e5c31af7Sopenharmony_ci		<< "\thighp uint invocationId = uint(gl_PrimitiveID);\n";
1326e5c31af7Sopenharmony_ci
1327e5c31af7Sopenharmony_ci	generateExecBufferIo(src, shaderSpec, "invocationId");
1328e5c31af7Sopenharmony_ci
1329e5c31af7Sopenharmony_ci	src << "}\n";
1330e5c31af7Sopenharmony_ci
1331e5c31af7Sopenharmony_ci	return src.str();
1332e5c31af7Sopenharmony_ci}
1333e5c31af7Sopenharmony_ci
1334e5c31af7Sopenharmony_cistatic std::string generateEmptyTessEvalShader (glu::GLSLVersion version)
1335e5c31af7Sopenharmony_ci{
1336e5c31af7Sopenharmony_ci	std::ostringstream src;
1337e5c31af7Sopenharmony_ci
1338e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(version) << "\n";
1339e5c31af7Sopenharmony_ci
1340e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(version) && version <= glu::GLSL_VERSION_310_ES)
1341e5c31af7Sopenharmony_ci		src << "#extension GL_EXT_tessellation_shader : require\n\n";
1342e5c31af7Sopenharmony_ci
1343e5c31af7Sopenharmony_ci	src << "layout(triangles, ccw) in;\n";
1344e5c31af7Sopenharmony_ci
1345e5c31af7Sopenharmony_ci	src << "\nvoid main (void)\n{\n"
1346e5c31af7Sopenharmony_ci		<< "\tgl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
1347e5c31af7Sopenharmony_ci		<< "}\n";
1348e5c31af7Sopenharmony_ci
1349e5c31af7Sopenharmony_ci	return src.str();
1350e5c31af7Sopenharmony_ci}
1351e5c31af7Sopenharmony_ci
1352e5c31af7Sopenharmony_ciTessControlExecutor::TessControlExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1353e5c31af7Sopenharmony_ci	: BufferIoExecutor	(renderCtx, shaderSpec, glu::ProgramSources()
1354e5c31af7Sopenharmony_ci							<< glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
1355e5c31af7Sopenharmony_ci							<< glu::TessellationControlSource(generateTessControlShader(shaderSpec))
1356e5c31af7Sopenharmony_ci							<< glu::TessellationEvaluationSource(generateEmptyTessEvalShader(shaderSpec.version))
1357e5c31af7Sopenharmony_ci							<< glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
1358e5c31af7Sopenharmony_ci{
1359e5c31af7Sopenharmony_ci}
1360e5c31af7Sopenharmony_ci
1361e5c31af7Sopenharmony_ciTessControlExecutor::~TessControlExecutor (void)
1362e5c31af7Sopenharmony_ci{
1363e5c31af7Sopenharmony_ci}
1364e5c31af7Sopenharmony_ci
1365e5c31af7Sopenharmony_civoid TessControlExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
1366e5c31af7Sopenharmony_ci{
1367e5c31af7Sopenharmony_ci	const glw::Functions&	gl	= m_renderCtx.getFunctions();
1368e5c31af7Sopenharmony_ci
1369e5c31af7Sopenharmony_ci	initBuffers(numValues);
1370e5c31af7Sopenharmony_ci
1371e5c31af7Sopenharmony_ci	// Setup input buffer & copy data
1372e5c31af7Sopenharmony_ci	uploadInputBuffer(inputs, numValues);
1373e5c31af7Sopenharmony_ci
1374e5c31af7Sopenharmony_ci	if (!m_inputs.empty())
1375e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
1376e5c31af7Sopenharmony_ci
1377e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
1378e5c31af7Sopenharmony_ci
1379e5c31af7Sopenharmony_ci	deUint32 vertexArray;
1380e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &vertexArray);
1381e5c31af7Sopenharmony_ci	gl.bindVertexArray(vertexArray);
1382e5c31af7Sopenharmony_ci
1383e5c31af7Sopenharmony_ci	// Render patches
1384e5c31af7Sopenharmony_ci	gl.patchParameteri(GL_PATCH_VERTICES, 3);
1385e5c31af7Sopenharmony_ci	gl.drawArrays(GL_PATCHES, 0, 3*numValues);
1386e5c31af7Sopenharmony_ci
1387e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
1388e5c31af7Sopenharmony_ci	gl.deleteVertexArrays(1, &vertexArray);
1389e5c31af7Sopenharmony_ci
1390e5c31af7Sopenharmony_ci	// Read back data
1391e5c31af7Sopenharmony_ci	readOutputBuffer(outputs, numValues);
1392e5c31af7Sopenharmony_ci}
1393e5c31af7Sopenharmony_ci
1394e5c31af7Sopenharmony_ci// TessEvaluationExecutor
1395e5c31af7Sopenharmony_ci
1396e5c31af7Sopenharmony_ciclass TessEvaluationExecutor : public BufferIoExecutor
1397e5c31af7Sopenharmony_ci{
1398e5c31af7Sopenharmony_cipublic:
1399e5c31af7Sopenharmony_ci	static TessEvaluationExecutor*	create					(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
1400e5c31af7Sopenharmony_ci
1401e5c31af7Sopenharmony_ci									~TessEvaluationExecutor	(void);
1402e5c31af7Sopenharmony_ci
1403e5c31af7Sopenharmony_ci	void							execute					(int numValues, const void* const* inputs, void* const* outputs);
1404e5c31af7Sopenharmony_ci
1405e5c31af7Sopenharmony_ci
1406e5c31af7Sopenharmony_ciprotected:
1407e5c31af7Sopenharmony_ci	static std::string				generateTessEvalShader	(const ShaderSpec& shaderSpec);
1408e5c31af7Sopenharmony_ci
1409e5c31af7Sopenharmony_ciprivate:
1410e5c31af7Sopenharmony_ci									TessEvaluationExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
1411e5c31af7Sopenharmony_ci};
1412e5c31af7Sopenharmony_ci
1413e5c31af7Sopenharmony_ciTessEvaluationExecutor* TessEvaluationExecutor::create (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1414e5c31af7Sopenharmony_ci{
1415e5c31af7Sopenharmony_ci	checkTessSupport(renderCtx, shaderSpec, glu::SHADERTYPE_TESSELLATION_EVALUATION);
1416e5c31af7Sopenharmony_ci
1417e5c31af7Sopenharmony_ci	return new TessEvaluationExecutor(renderCtx, shaderSpec);
1418e5c31af7Sopenharmony_ci}
1419e5c31af7Sopenharmony_ci
1420e5c31af7Sopenharmony_cistatic std::string generatePassthroughTessControlShader (glu::GLSLVersion version)
1421e5c31af7Sopenharmony_ci{
1422e5c31af7Sopenharmony_ci	std::ostringstream src;
1423e5c31af7Sopenharmony_ci
1424e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(version) << "\n";
1425e5c31af7Sopenharmony_ci
1426e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(version) && version <= glu::GLSL_VERSION_310_ES)
1427e5c31af7Sopenharmony_ci		src << "#extension GL_EXT_tessellation_shader : require\n\n";
1428e5c31af7Sopenharmony_ci
1429e5c31af7Sopenharmony_ci	src << "layout(vertices = 1) out;\n\n";
1430e5c31af7Sopenharmony_ci
1431e5c31af7Sopenharmony_ci	src << "void main (void)\n{\n";
1432e5c31af7Sopenharmony_ci
1433e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < 2; ndx++)
1434e5c31af7Sopenharmony_ci		src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
1435e5c31af7Sopenharmony_ci
1436e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < 4; ndx++)
1437e5c31af7Sopenharmony_ci		src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
1438e5c31af7Sopenharmony_ci
1439e5c31af7Sopenharmony_ci	src << "}\n";
1440e5c31af7Sopenharmony_ci
1441e5c31af7Sopenharmony_ci	return src.str();
1442e5c31af7Sopenharmony_ci}
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_cistd::string TessEvaluationExecutor::generateTessEvalShader (const ShaderSpec& shaderSpec)
1445e5c31af7Sopenharmony_ci{
1446e5c31af7Sopenharmony_ci	std::ostringstream src;
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1449e5c31af7Sopenharmony_ci
1450e5c31af7Sopenharmony_ci	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
1451e5c31af7Sopenharmony_ci		src << "#extension GL_EXT_tessellation_shader : require\n";
1452e5c31af7Sopenharmony_ci
1453e5c31af7Sopenharmony_ci	if (!shaderSpec.globalDeclarations.empty())
1454e5c31af7Sopenharmony_ci		src << shaderSpec.globalDeclarations << "\n";
1455e5c31af7Sopenharmony_ci
1456e5c31af7Sopenharmony_ci	src << "\n";
1457e5c31af7Sopenharmony_ci
1458e5c31af7Sopenharmony_ci	src << "layout(isolines, equal_spacing) in;\n\n";
1459e5c31af7Sopenharmony_ci
1460e5c31af7Sopenharmony_ci	declareBufferBlocks(src, shaderSpec);
1461e5c31af7Sopenharmony_ci
1462e5c31af7Sopenharmony_ci	src << "void main (void)\n{\n"
1463e5c31af7Sopenharmony_ci		<< "\tgl_Position = vec4(gl_TessCoord.x, 0.0, 0.0, 1.0);\n"
1464e5c31af7Sopenharmony_ci		<< "\thighp uint invocationId = uint(gl_PrimitiveID)*2u + (gl_TessCoord.x > 0.5 ? 1u : 0u);\n";
1465e5c31af7Sopenharmony_ci
1466e5c31af7Sopenharmony_ci	generateExecBufferIo(src, shaderSpec, "invocationId");
1467e5c31af7Sopenharmony_ci
1468e5c31af7Sopenharmony_ci	src	<< "}\n";
1469e5c31af7Sopenharmony_ci
1470e5c31af7Sopenharmony_ci	return src.str();
1471e5c31af7Sopenharmony_ci}
1472e5c31af7Sopenharmony_ci
1473e5c31af7Sopenharmony_ciTessEvaluationExecutor::TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1474e5c31af7Sopenharmony_ci	: BufferIoExecutor	(renderCtx, shaderSpec, glu::ProgramSources()
1475e5c31af7Sopenharmony_ci							<< glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
1476e5c31af7Sopenharmony_ci							<< glu::TessellationControlSource(generatePassthroughTessControlShader(shaderSpec.version))
1477e5c31af7Sopenharmony_ci							<< glu::TessellationEvaluationSource(generateTessEvalShader(shaderSpec))
1478e5c31af7Sopenharmony_ci							<< glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
1479e5c31af7Sopenharmony_ci{
1480e5c31af7Sopenharmony_ci}
1481e5c31af7Sopenharmony_ci
1482e5c31af7Sopenharmony_ciTessEvaluationExecutor::~TessEvaluationExecutor (void)
1483e5c31af7Sopenharmony_ci{
1484e5c31af7Sopenharmony_ci}
1485e5c31af7Sopenharmony_ci
1486e5c31af7Sopenharmony_civoid TessEvaluationExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
1487e5c31af7Sopenharmony_ci{
1488e5c31af7Sopenharmony_ci	const glw::Functions&	gl				= m_renderCtx.getFunctions();
1489e5c31af7Sopenharmony_ci	const int				alignedValues	= deAlign32(numValues, 2);
1490e5c31af7Sopenharmony_ci
1491e5c31af7Sopenharmony_ci	// Initialize buffers with aligned value count to make room for padding
1492e5c31af7Sopenharmony_ci	initBuffers(alignedValues);
1493e5c31af7Sopenharmony_ci
1494e5c31af7Sopenharmony_ci	// Setup input buffer & copy data
1495e5c31af7Sopenharmony_ci	uploadInputBuffer(inputs, numValues);
1496e5c31af7Sopenharmony_ci
1497e5c31af7Sopenharmony_ci	// \todo [2014-06-26 pyry] Duplicate last value in the buffer to prevent infinite loops for example?
1498e5c31af7Sopenharmony_ci
1499e5c31af7Sopenharmony_ci	if (!m_inputs.empty())
1500e5c31af7Sopenharmony_ci		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
1501e5c31af7Sopenharmony_ci
1502e5c31af7Sopenharmony_ci	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
1503e5c31af7Sopenharmony_ci
1504e5c31af7Sopenharmony_ci	deUint32 vertexArray;
1505e5c31af7Sopenharmony_ci	gl.genVertexArrays(1, &vertexArray);
1506e5c31af7Sopenharmony_ci	gl.bindVertexArray(vertexArray);
1507e5c31af7Sopenharmony_ci
1508e5c31af7Sopenharmony_ci	// Render patches
1509e5c31af7Sopenharmony_ci	gl.patchParameteri(GL_PATCH_VERTICES, 2);
1510e5c31af7Sopenharmony_ci	gl.drawArrays(GL_PATCHES, 0, alignedValues);
1511e5c31af7Sopenharmony_ci
1512e5c31af7Sopenharmony_ci	gl.bindVertexArray(0);
1513e5c31af7Sopenharmony_ci	gl.deleteVertexArrays(1, &vertexArray);
1514e5c31af7Sopenharmony_ci
1515e5c31af7Sopenharmony_ci	// Read back data
1516e5c31af7Sopenharmony_ci	readOutputBuffer(outputs, numValues);
1517e5c31af7Sopenharmony_ci}
1518e5c31af7Sopenharmony_ci
1519e5c31af7Sopenharmony_ci// Utilities
1520e5c31af7Sopenharmony_ci
1521e5c31af7Sopenharmony_ciShaderExecutor* createExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const ShaderSpec& shaderSpec)
1522e5c31af7Sopenharmony_ci{
1523e5c31af7Sopenharmony_ci	switch (shaderType)
1524e5c31af7Sopenharmony_ci	{
1525e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_VERTEX:					return new VertexShaderExecutor			(renderCtx, shaderSpec);
1526e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_TESSELLATION_CONTROL:		return TessControlExecutor::create		(renderCtx, shaderSpec);
1527e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_TESSELLATION_EVALUATION:	return TessEvaluationExecutor::create	(renderCtx, shaderSpec);
1528e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_GEOMETRY:					return GeometryShaderExecutor::create	(renderCtx, shaderSpec);
1529e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_FRAGMENT:					return new FragmentShaderExecutor		(renderCtx, shaderSpec);
1530e5c31af7Sopenharmony_ci		case glu::SHADERTYPE_COMPUTE:					return new ComputeShaderExecutor		(renderCtx, shaderSpec);
1531e5c31af7Sopenharmony_ci		default:
1532e5c31af7Sopenharmony_ci			throw tcu::InternalError("Unsupported shader type");
1533e5c31af7Sopenharmony_ci	}
1534e5c31af7Sopenharmony_ci}
1535e5c31af7Sopenharmony_ci
1536e5c31af7Sopenharmony_cibool  executorSupported(glu::ShaderType shaderType)
1537e5c31af7Sopenharmony_ci{
1538e5c31af7Sopenharmony_ci	switch (shaderType)
1539e5c31af7Sopenharmony_ci	{
1540e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_VERTEX:
1541e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_TESSELLATION_CONTROL:
1542e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1543e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_GEOMETRY:
1544e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_FRAGMENT:
1545e5c31af7Sopenharmony_ci	case glu::SHADERTYPE_COMPUTE:
1546e5c31af7Sopenharmony_ci		return true;
1547e5c31af7Sopenharmony_ci	default:
1548e5c31af7Sopenharmony_ci		return false;
1549e5c31af7Sopenharmony_ci	}
1550e5c31af7Sopenharmony_ci}
1551e5c31af7Sopenharmony_ci
1552e5c31af7Sopenharmony_ci} // ShaderExecUtil
1553e5c31af7Sopenharmony_ci} // gls
1554e5c31af7Sopenharmony_ci} // deqp
1555