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