13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program OpenGL (ES) Module
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * -----------------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Shader execution utilities.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glsShaderExecUtil.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluRenderContext.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluDrawUtil.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluObjectWrapper.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluShaderProgram.hpp"
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluTextureUtil.hpp"
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluProgramInterfaceQuery.hpp"
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluPixelTransfer.hpp"
32582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry#include "gluStrUtil.hpp"
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTestLog.hpp"
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwFunctions.hpp"
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glwEnums.hpp"
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deSTLUtil.hpp"
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deStringUtil.hpp"
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deUniquePtr.hpp"
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMemory.h"
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <map>
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace deqp
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace gls
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace ShaderExecUtil
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector;
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool isExtensionSupported (const glu::RenderContext& renderCtx, const std::string& extension)
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl		= renderCtx.getFunctions();
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int						numExts	= 0;
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < numExts; ndx++)
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const char* curExt = (const char*)gl.getStringi(GL_EXTENSIONS, ndx);
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (extension == curExt)
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return true;
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return false;
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void checkExtension (const glu::RenderContext& renderCtx, const std::string& extension)
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!isExtensionSupported(renderCtx, extension))
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::NotSupportedError(extension + " is not supported");
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
77582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyrystatic void checkLimit (const glu::RenderContext& renderCtx, deUint32 pname, int required)
78582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry{
79582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	const glw::Functions&	gl					= renderCtx.getFunctions();
80582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	int						implementationLimit	= -1;
81582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	deUint32				error;
82582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
83582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	gl.getIntegerv(pname, &implementationLimit);
84582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	error = gl.getError();
85582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
86582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	if (error != GL_NO_ERROR)
87582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		throw tcu::TestError("Failed to query " + de::toString(glu::getGettableStateStr(pname)) + " - got " + de::toString(glu::getErrorStr(error)));
88582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	if (implementationLimit < required)
89582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) + " >= " + de::toString(required) + ", got " + de::toString(implementationLimit));
90582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry}
91582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Shader utilities
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateVertexShader (const ShaderSpec& shaderSpec)
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			usesInout	= glu::glslVersionUsesInOutQualifiers(shaderSpec.version);
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			in			= usesInout ? "in"		: "attribute";
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const char*			out			= usesInout ? "out"		: "varying";
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!shaderSpec.globalDeclarations.empty())
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << shaderSpec.globalDeclarations << "\n";
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << in << " " << glu::declare(input->varType, input->name) << ";\n";
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(output->varType.isBasicType());
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType		intType		(intBaseType, glu::PRECISION_HIGHP);
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "flat " << out << " " << glu::declare(intType, "o_" + output->name) << ";\n";
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "flat " << out << " " << glu::declare(output->varType, output->name) << ";\n";
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n"
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "void main (void)\n"
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_Position = vec4(0.0);\n"
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_PointSize = 1.0;\n\n";
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Declare necessary output variables (bools).
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << glu::declare(output->varType, output->name) << ";\n";
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Operation - indented to correct level.
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::istringstream	opSrc	(shaderSpec.source);
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::string			line;
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (std::getline(opSrc, line))
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << line << "\n";
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Assignments to outputs.
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateGeometryShader (const ShaderSpec& shaderSpec)
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "#extension GL_EXT_geometry_shader : require\n";
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!shaderSpec.globalDeclarations.empty())
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << shaderSpec.globalDeclarations << "\n";
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "layout(points) in;\n"
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "layout(points, max_vertices = 1) out;\n";
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "flat in " << glu::declare(input->varType, "geom_" + input->name) << "[];\n";
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(output->varType.isBasicType());
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType		intType		(intBaseType, glu::PRECISION_HIGHP);
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "flat out " << glu::declare(intType, "o_" + output->name) << ";\n";
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "flat out " << glu::declare(output->varType, output->name) << ";\n";
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n"
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "void main (void)\n"
2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_Position = gl_in[0].gl_Position;\n\n";
2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Fetch input variables
2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\t" << glu::declare(input->varType, input->name) << " = geom_" << input->name << "[0];\n";
2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Declare necessary output variables (bools).
2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << glu::declare(output->varType, output->name) << ";\n";
2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n";
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Operation - indented to correct level.
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::istringstream	opSrc	(shaderSpec.source);
2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::string			line;
2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (std::getline(opSrc, line))
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << line << "\n";
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Assignments to outputs.
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "	EmitVertex();\n"
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	EndPrimitive();\n"
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "}\n";
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateEmptyFragmentSource (glu::GLSLVersion version)
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool			customOut		= glu::glslVersionUsesInOutQualifiers(version);
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(version) << "\n";
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \todo [2013-08-05 pyry] Do we need one dummy output?
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n{\n";
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!customOut)
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "	gl_FragColor = vec4(0.0);\n";
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generatePassthroughVertexShader (const ShaderSpec& shaderSpec, const char* inputPrefix, const char* outputPrefix)
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// flat qualifier is not present in earlier versions?
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "in highp vec4 a_position;\n";
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n";
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\nvoid main (void)\n{\n"
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_Position = a_position;\n"
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_PointSize = 1.0;\n";
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n";
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap)
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!shaderSpec.globalDeclarations.empty())
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << shaderSpec.globalDeclarations << "\n";
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "flat in " << glu::declare(input->varType, input->name) << ";\n";
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx)
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&				output		= shaderSpec.outputs[outNdx];
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int					location	= de::lookup(outLocationMap, output.name);
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const std::string			outVarName	= "o_" + output.name;
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::VariableDeclaration	decl		(output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(location));
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK_INTERNAL(output.varType.isBasicType());
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType()))
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			vecSize			= glu::getDataTypeScalarSize(output.varType.getBasicType());
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType	uintBasicType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType	uintType		(uintBasicType, glu::PRECISION_HIGHP);
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			decl.varType = uintType;
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << decl << ";\n";
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType()))
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			vecSize			= glu::getDataTypeScalarSize(output.varType.getBasicType());
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType	intBasicType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType	intType			(intBasicType, glu::PRECISION_HIGHP);
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			decl.varType = intType;
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << decl << ";\n";
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeMatrix(output.varType.getBasicType()))
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			vecSize			= glu::getDataTypeMatrixNumRows(output.varType.getBasicType());
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			numVecs			= glu::getDataTypeMatrixNumColumns(output.varType.getBasicType());
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType	uintBasicType	= glu::getDataTypeUintVec(vecSize);
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType	uintType		(uintBasicType, glu::PRECISION_HIGHP);
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			decl.varType = uintType;
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				decl.name				= outVarName + "_" + de::toString(vecNdx);
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				decl.layout.location	= location + vecNdx;
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				src << decl << ";\n";
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << glu::VariableDeclaration(output.varType, output.name, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, location) << ";\n";
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\nvoid main (void)\n{\n";
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if ((useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType())) ||
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glu::isDataTypeBoolOrBVec(output->varType.getBasicType()) ||
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			glu::isDataTypeMatrix(output->varType.getBasicType()))
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << glu::declare(output->varType, output->name) << ";\n";
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Operation - indented to correct level.
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::istringstream	opSrc	(shaderSpec.source);
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::string			line;
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (std::getline(opSrc, line))
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << line << "\n";
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType()))
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "	o_" << output->name << " = floatBitsToUint(" << output->name << ");\n";
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeMatrix(output->varType.getBasicType()))
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			numVecs			= glu::getDataTypeMatrixNumColumns(output->varType.getBasicType());
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (useIntOutputs)
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					src << "\to_" << output->name << "_" << vecNdx << " = floatBitsToUint(" << output->name << "[" << vecNdx << "]);\n";
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					src << "\to_" << output->name << "_" << vecNdx << " = " << output->name << "[" << vecNdx << "];\n";
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				vecSize		= glu::getDataTypeScalarSize(output->varType.getBasicType());
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intBaseType	= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\to_" << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// ShaderExecutor
3983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3993c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderExecutor::ShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_renderCtx	(renderCtx)
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_inputs		(shaderSpec.inputs)
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_outputs		(shaderSpec.outputs)
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4063c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderExecutor::~ShaderExecutor (void)
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderExecutor::useProgram (void)
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(isOk());
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_renderCtx.getFunctions().useProgram(getProgram());
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// VertexProcessorExecutor (base class for vertex and geometry executors)
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass VertexProcessorExecutor : public ShaderExecutor
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								VertexProcessorExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources);
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								~VertexProcessorExecutor(void);
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool						isOk					(void) const				{ return m_program.isOk();			}
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						log						(tcu::TestLog& dst) const	{ dst << m_program;					}
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32					getProgram				(void) const				{ return m_program.getProgram();	}
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						execute					(int numValues, const void* const* inputs, void* const* outputs);
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::ShaderProgram			m_program;
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename Iterator>
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct SymbolNameIterator
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	Iterator symbolIter;
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SymbolNameIterator (Iterator symbolIter_) : symbolIter(symbolIter_) {}
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	inline SymbolNameIterator&	operator++	(void)								{ ++symbolIter; return *this;				}
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	inline bool					operator==	(const SymbolNameIterator& other)	{ return symbolIter == other.symbolIter;	}
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	inline bool					operator!=	(const SymbolNameIterator& other)	{ return symbolIter != other.symbolIter;	}
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	inline std::string operator* (void) const
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeBoolOrBVec(symbolIter->varType.getBasicType()))
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return "o_" + symbolIter->name;
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return symbolIter->name;
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename Iterator>
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline glu::TransformFeedbackVaryings<SymbolNameIterator<Iterator> > getTFVaryings (Iterator begin, Iterator end)
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return glu::TransformFeedbackVaryings<SymbolNameIterator<Iterator> >(SymbolNameIterator<Iterator>(begin), SymbolNameIterator<Iterator>(end));
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4613c827367444ee418f129b2c238299f49d3264554Jarkko PoyryVertexProcessorExecutor::VertexProcessorExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources)
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: ShaderExecutor	(renderCtx, shaderSpec)
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_program			(renderCtx,
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						 glu::ProgramSources(sources) << getTFVaryings(shaderSpec.outputs.begin(), shaderSpec.outputs.end())
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													  << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS))
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4693c827367444ee418f129b2c238299f49d3264554Jarkko PoyryVertexProcessorExecutor::~VertexProcessorExecutor (void)
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename Iterator>
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic int computeTotalScalarSize (Iterator begin, Iterator end)
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int size = 0;
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (Iterator cur = begin; cur != end; ++cur)
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		size += cur->varType.getScalarSize();
4793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return size;
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4823c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid VertexProcessorExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&					gl					= m_renderCtx.getFunctions();
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool								useTFObject			= isContextTypeES(m_renderCtx.getType()) || (isContextTypeGLCore(m_renderCtx.getType()) && m_renderCtx.getType().getMajorVersion() >= 4);
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<glu::VertexArrayBinding>			vertexArrays;
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	de::UniquePtr<glu::TransformFeedback>	transformFeedback	(useTFObject ? new glu::TransformFeedback(m_renderCtx) : DE_NULL);
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::Buffer								outputBuffer		(m_renderCtx);
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int								outputBufferStride	= computeTotalScalarSize(m_outputs.begin(), m_outputs.end())*sizeof(deUint32);
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup inputs.
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++)
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&		symbol		= m_inputs[inputNdx];
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const void*			ptr			= inputs[inputNdx];
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	basicType	= symbol.varType.getBasicType();
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(basicType);
4983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(basicType))
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Float(symbol.name, vecSize, numValues, 0, (const float*)ptr));
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeIntOrIVec(basicType))
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Int32(symbol.name, vecSize, numValues, 0, (const deInt32*)ptr));
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeUintOrUVec(basicType))
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Uint32(symbol.name, vecSize, numValues, 0, (const deUint32*)ptr));
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeMatrix(basicType))
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		numRows	= glu::getDataTypeMatrixNumRows(basicType);
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		numCols	= glu::getDataTypeMatrixNumColumns(basicType);
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		stride	= numRows * numCols * sizeof(float);
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int colNdx = 0; colNdx < numCols; ++colNdx)
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				vertexArrays.push_back(glu::va::Float(symbol.name, colNdx, numRows, numValues, stride, ((const float*)ptr) + colNdx * numRows));
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
5163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup TF outputs.
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (useTFObject)
5203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, **transformFeedback);
5213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *outputBuffer);
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, outputBufferStride*numValues, DE_NULL, GL_STREAM_READ);
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *outputBuffer);
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Error in TF setup");
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Draw with rasterization disabled.
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.beginTransformFeedback(GL_POINTS);
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.enable(GL_RASTERIZER_DISCARD);
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::draw(m_renderCtx, m_program.getProgram(), (int)vertexArrays.size(), vertexArrays.empty() ? DE_NULL : &vertexArrays[0],
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  glu::pr::Points(numValues));
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.disable(GL_RASTERIZER_DISCARD);
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.endTransformFeedback();
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw");
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back data.
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const void*	srcPtr		= gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, outputBufferStride*numValues, GL_MAP_READ_BIT);
5383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int			curOffset	= 0; // Offset in buffer in bytes.
5393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER)");
5413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK(srcPtr != DE_NULL);
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const Symbol&		symbol		= m_outputs[outputNdx];
5463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			void*				dstPtr		= outputs[outputNdx];
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int			scalarSize	= symbol.varType.getScalarSize();
5483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues; ndx++)
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deMemcpy((deUint32*)dstPtr + scalarSize*ndx, (const deUint8*)srcPtr + curOffset + ndx*outputBufferStride, scalarSize*sizeof(deUint32));
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset += scalarSize*sizeof(deUint32);
5533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (useTFObject)
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
5613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Restore state");
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// VertexShaderExecutor
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass VertexShaderExecutor : public VertexProcessorExecutor
5683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								VertexShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5733c827367444ee418f129b2c238299f49d3264554Jarkko PoyryVertexShaderExecutor::VertexShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: VertexProcessorExecutor	(renderCtx, shaderSpec,
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								 glu::ProgramSources() << glu::VertexSource(generateVertexShader(shaderSpec))
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// GeometryShaderExecutor
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5828852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyryclass CheckGeomSupport
5838852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry{
5848852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyrypublic:
5858852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	inline CheckGeomSupport (const glu::RenderContext& renderCtx)
5868852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	{
5878852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES)
5888852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			checkExtension(renderCtx, "GL_EXT_geometry_shader");
5898852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	}
5908852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry};
5918852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry
5928852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyryclass GeometryShaderExecutor : private CheckGeomSupport, public VertexProcessorExecutor
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								GeometryShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5983c827367444ee418f129b2c238299f49d3264554Jarkko PoyryGeometryShaderExecutor::GeometryShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
5998852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	: CheckGeomSupport			(renderCtx)
6008852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	, VertexProcessorExecutor	(renderCtx, shaderSpec,
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "", "geom_"))
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   << glu::GeometrySource(generateGeometryShader(shaderSpec))
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													   << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// FragmentShaderExecutor
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FragmentShaderExecutor : public ShaderExecutor
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
6123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								FragmentShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
6133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								~FragmentShaderExecutor	(void);
6143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool						isOk					(void) const				{ return m_program.isOk();			}
6163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						log						(tcu::TestLog& dst) const	{ dst << m_program;					}
6173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32					getProgram				(void) const				{ return m_program.getProgram();	}
6183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void						execute					(int numValues, const void* const* inputs, void* const* outputs);
6203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6213c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
6223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::vector<const Symbol*>	m_outLocationSymbols;
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::map<std::string, int>	m_outLocationMap;
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::ShaderProgram			m_program;
6253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6273c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::map<std::string, int> generateLocationMap (const std::vector<Symbol>& symbols, std::vector<const Symbol*>& locationSymbols)
6283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::map<std::string, int>	ret;
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int							location	= 0;
6313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	locationSymbols.clear();
6333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it)
6353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int	numLocations	= glu::getDataTypeNumLocations(it->varType.getBasicType());
6373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_CHECK_INTERNAL(!de::contains(ret, it->name));
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::insert(ret, it->name, location);
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		location += numLocations;
6413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int ndx = 0; ndx < numLocations; ++ndx)
6433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			locationSymbols.push_back(&*it);
6443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return ret;
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline bool hasFloatRenderTargets (const glu::RenderContext& renderCtx)
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::ContextType type = renderCtx.getType();
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return glu::isContextTypeGLCore(type);
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6553c827367444ee418f129b2c238299f49d3264554Jarkko PoyryFragmentShaderExecutor::FragmentShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: ShaderExecutor		(renderCtx, shaderSpec)
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_outLocationSymbols	()
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_outLocationMap		(generateLocationMap(m_outputs, m_outLocationSymbols))
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_program				(renderCtx,
6603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							 glu::ProgramSources() << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", ""))
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry												   << glu::FragmentSource(generateFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx), m_outLocationMap)))
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6653c827367444ee418f129b2c238299f49d3264554Jarkko PoyryFragmentShaderExecutor::~FragmentShaderExecutor (void)
6663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline int queryInt (const glw::Functions& gl, deUint32 pname)
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int value = 0;
6723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.getIntegerv(pname, &value);
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return value;
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic tcu::TextureFormat getRenderbufferFormatForOutput (const glu::VarType& outputType, bool useIntOutputs)
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::TextureFormat::ChannelOrder channelOrderMap[] =
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TextureFormat::R,
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TextureFormat::RG,
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TextureFormat::RGBA,	// No RGB variants available.
6833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TextureFormat::RGBA
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::DataType					basicType		= outputType.getBasicType();
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int							numComps		= glu::getDataTypeNumComponents(basicType);
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TextureFormat::ChannelType		channelType;
6893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (glu::getDataTypeScalarType(basicType))
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::TYPE_UINT:	channelType = tcu::TextureFormat::UNSIGNED_INT32;												break;
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::TYPE_INT:		channelType = tcu::TextureFormat::SIGNED_INT32;													break;
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::TYPE_BOOL:	channelType = tcu::TextureFormat::SIGNED_INT32;													break;
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::TYPE_FLOAT:	channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT;	break;
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::InternalError("Invalid output type");
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap)));
7013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::TextureFormat(channelOrderMap[numComps-1], channelType);
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid FragmentShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&			gl					= m_renderCtx.getFunctions();
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const bool						useIntOutputs		= !hasFloatRenderTargets(m_renderCtx);
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int						maxRenderbufferSize	= queryInt(gl, GL_MAX_RENDERBUFFER_SIZE);
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int						framebufferW		= de::min(maxRenderbufferSize, numValues);
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int						framebufferH		= (numValues / framebufferW) + ((numValues % framebufferW != 0) ? 1 : 0);
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::Framebuffer				framebuffer			(m_renderCtx);
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::RenderbufferVector			renderbuffers		(m_renderCtx, m_outLocationSymbols.size());
7153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<glu::VertexArrayBinding>	vertexArrays;
7173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<tcu::Vec2>				positions			(numValues);
7183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (framebufferH > maxRenderbufferSize)
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::NotSupportedError("Value count is too high for maximum supported renderbuffer size");
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Compute positions - 1px points are used to drive fragment shading.
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int valNdx = 0; valNdx < numValues; valNdx++)
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		ix		= valNdx % framebufferW;
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		iy		= valNdx / framebufferW;
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float		fx		= -1.0f + 2.0f*((float(ix) + 0.5f) / float(framebufferW));
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float		fy		= -1.0f + 2.0f*((float(iy) + 0.5f) / float(framebufferH));
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		positions[valNdx] = tcu::Vec2(fx, fy);
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Vertex inputs.
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vertexArrays.push_back(glu::va::Float("a_position", 2, numValues, 0, (const float*)&positions[0]));
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++)
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&		symbol		= m_inputs[inputNdx];
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const std::string	attribName	= "a_" + symbol.name;
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const void*			ptr			= inputs[inputNdx];
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	basicType	= symbol.varType.getBasicType();
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(basicType);
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(basicType))
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Float(attribName, vecSize, numValues, 0, (const float*)ptr));
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeIntOrIVec(basicType))
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Int32(attribName, vecSize, numValues, 0, (const deInt32*)ptr));
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeUintOrUVec(basicType))
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			vertexArrays.push_back(glu::va::Uint32(attribName, vecSize, numValues, 0, (const deUint32*)ptr));
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeMatrix(basicType))
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		numRows	= glu::getDataTypeMatrixNumRows(basicType);
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		numCols	= glu::getDataTypeMatrixNumColumns(basicType);
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int		stride	= numRows * numCols * sizeof(float);
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int colNdx = 0; colNdx < numCols; ++colNdx)
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				vertexArrays.push_back(glu::va::Float(attribName, colNdx, numRows, numValues, stride, ((const float*)ptr) + colNdx * numRows));
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Construct framebuffer.
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int outNdx = 0; outNdx < (int)m_outLocationSymbols.size(); ++outNdx)
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&	output			= *m_outLocationSymbols[outNdx];
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	renderbuffer	= renderbuffers[outNdx];
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	format			= glu::getInternalFormat(getRenderbufferFormatForOutput(output.varType, useIntOutputs));
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.renderbufferStorage(GL_RENDERBUFFER, format, framebufferW, framebufferH);
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+outNdx, GL_RENDERBUFFER, renderbuffer);
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up framebuffer object");
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<deUint32> drawBuffers(m_outLocationSymbols.size());
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int ndx = 0; ndx < (int)m_outLocationSymbols.size(); ndx++)
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			drawBuffers[ndx] = GL_COLOR_ATTACHMENT0+ndx;
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]);
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffers()");
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Render
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.viewport(0, 0, framebufferW, framebufferH);
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::draw(m_renderCtx, m_program.getProgram(), (int)vertexArrays.size(), &vertexArrays[0],
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			  glu::pr::Points(numValues));
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw");
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back pixels.
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TextureLevel	tmpBuf;
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \todo [2013-08-07 pyry] Some fast-paths could be added here.
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int outNdx = 0; outNdx < (int)m_outputs.size(); ++outNdx)
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const Symbol&				output			= m_outputs[outNdx];
8033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int					outSize			= output.varType.getScalarSize();
8043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int					outVecSize		= glu::getDataTypeNumComponents(output.varType.getBasicType());
8053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int					outNumLocs		= glu::getDataTypeNumLocations(output.varType.getBasicType());
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deUint32*					dstPtrBase		= static_cast<deUint32*>(outputs[outNdx]);
8073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::TextureFormat	format			= getRenderbufferFormatForOutput(output.varType, useIntOutputs);
8083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const tcu::TextureFormat	readFormat		(tcu::TextureFormat::RGBA, format.type);
8093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int					outLocation		= de::lookup(m_outLocationMap, output.name);
8103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tmpBuf.setStorage(readFormat, framebufferW, framebufferH);
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int locNdx = 0; locNdx < outNumLocs; ++locNdx)
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				gl.readBuffer(GL_COLOR_ATTACHMENT0 + outLocation + locNdx);
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				glu::readPixels(m_renderCtx, 0, 0, tmpBuf.getAccess());
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels");
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (outSize == 4 && outNumLocs == 1)
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues*outVecSize*sizeof(deUint32));
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					for (int valNdx = 0; valNdx < numValues; valNdx++)
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						const deUint32* srcPtr = (const deUint32*)tmpBuf.getAccess().getDataPtr() + valNdx*4;
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						deUint32*		dstPtr = &dstPtrBase[outSize*valNdx + outVecSize*locNdx];
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						deMemcpy(dstPtr, srcPtr, outVecSize*sizeof(deUint32));
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \todo [2013-08-07 pyry] Clear draw buffers & viewport?
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Shared utilities for compute and tess executors
8393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic deUint32 getVecStd430ByteAlignment (glu::DataType type)
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (glu::getDataTypeScalarSize(type))
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 1:		return 4u;
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 2:		return 8u;
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 3:		return 16u;
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case 4:		return 16u;
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			return 0u;
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BufferIoExecutor : public ShaderExecutor
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						BufferIoExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources);
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						~BufferIoExecutor	(void);
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool				isOk				(void) const				{ return m_program.isOk();			}
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				log					(tcu::TestLog& dst) const	{ dst << m_program;					}
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32			getProgram			(void) const				{ return m_program.getProgram();	}
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum
8663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		INPUT_BUFFER_BINDING	= 0,
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		OUTPUT_BUFFER_BINDING	= 1,
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				initBuffers			(int numValues);
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32			getInputBuffer		(void) const		{ return *m_inputBuffer;					}
8733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32			getOutputBuffer		(void) const		{ return *m_outputBuffer;					}
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32			getInputStride		(void) const		{ return getLayoutStride(m_inputLayout);	}
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32			getOutputStride		(void) const		{ return getLayoutStride(m_outputLayout);	}
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				uploadInputBuffer	(const void* const* inputPtrs, int numValues);
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				readOutputBuffer	(void* const* outputPtrs, int numValues);
8793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void			declareBufferBlocks	(std::ostream& src, const ShaderSpec& spec);
8813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void			generateExecBufferIo(std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName);
8823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::ShaderProgram	m_program;
8843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8853c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
8863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	struct VarLayout
8873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint32		offset;
8893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint32		stride;
8903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		deUint32		matrixStride;
8913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		VarLayout (void) : offset(0), stride(0), matrixStride(0) {}
8933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
8943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				resizeInputBuffer	(int newSize);
8963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				resizeOutputBuffer	(int newSize);
8973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void			computeVarLayout	(const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout);
8993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static deUint32		getLayoutStride		(const vector<VarLayout>& layout);
9003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void			copyToBuffer		(const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
9023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static void			copyFromBuffer		(const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
9033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::Buffer			m_inputBuffer;
9053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::Buffer			m_outputBuffer;
9063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<VarLayout>	m_inputLayout;
9083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<VarLayout>	m_outputLayout;
9093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
9103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9113c827367444ee418f129b2c238299f49d3264554Jarkko PoyryBufferIoExecutor::BufferIoExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec, const glu::ProgramSources& sources)
9123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: ShaderExecutor	(renderCtx, shaderSpec)
9133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_program			(renderCtx, sources)
9143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_inputBuffer		(renderCtx)
9153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_outputBuffer	(renderCtx)
9163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	computeVarLayout(m_inputs, &m_inputLayout);
9183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	computeVarLayout(m_outputs, &m_outputLayout);
9193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9213c827367444ee418f129b2c238299f49d3264554Jarkko PoyryBufferIoExecutor::~BufferIoExecutor (void)
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::resizeInputBuffer (int newSize)
9263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions& gl = m_renderCtx.getFunctions();
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_inputBuffer);
9293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
9303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate input buffer");
9313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::resizeOutputBuffer (int newSize)
9343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions& gl = m_renderCtx.getFunctions();
9363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_outputBuffer);
9373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
9383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate output buffer");
9393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9413c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::initBuffers (int numValues)
9423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32		inputStride			= getLayoutStride(m_inputLayout);
9443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32		outputStride		= getLayoutStride(m_outputLayout);
9453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			inputBufferSize		= numValues * inputStride;
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			outputBufferSize	= numValues * outputStride;
9473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	resizeInputBuffer(inputBufferSize);
9493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	resizeOutputBuffer(outputBufferSize);
9503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
9513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9523c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout)
9533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32	maxAlignment	= 0;
9553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deUint32	curOffset		= 0;
9563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(layout->empty());
9583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	layout->resize(symbols.size());
9593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++)
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&		symbol		= symbols[varNdx];
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	basicType	= symbol.varType.getBasicType();
9643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		VarLayout&			layoutEntry	= (*layout)[varNdx];
9653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeScalarOrVector(basicType))
9673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	alignment	= getVecStd430ByteAlignment(basicType);
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	size		= (deUint32)glu::getDataTypeScalarSize(basicType)*sizeof(deUint32);
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset		= (deUint32)deAlign32((int)curOffset, (int)alignment);
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			maxAlignment	= de::max(maxAlignment, alignment);
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			layoutEntry.offset			= curOffset;
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			layoutEntry.matrixStride	= 0;
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset += size;
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else if (glu::isDataTypeMatrix(basicType))
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int				numVecs			= glu::getDataTypeMatrixNumColumns(basicType);
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		vecType			= glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType));
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32			vecAlignment	= getVecStd430ByteAlignment(vecType);
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset		= (deUint32)deAlign32((int)curOffset, (int)vecAlignment);
9863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			maxAlignment	= de::max(maxAlignment, vecAlignment);
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			layoutEntry.offset			= curOffset;
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			layoutEntry.matrixStride	= vecAlignment;
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset += vecAlignment*numVecs;
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(false);
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32	totalSize	= (deUint32)deAlign32(curOffset, maxAlignment);
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter)
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			varIter->stride = totalSize;
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 BufferIoExecutor::getLayoutStride (const vector<VarLayout>& layout)
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return layout.empty() ? 0 : layout[0].stride;
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (varType.isBasicType())
10133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		basicType		= varType.getBasicType();
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				isMatrix		= glu::isDataTypeMatrix(basicType);
10163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				numVecs			= isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
10183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				numComps		= scalarSize / numVecs;
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
10233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		srcOffset		= sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps);
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		dstOffset		= layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0);
10263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint8*	srcPtr			= (const deUint8*)srcBasePtr + srcOffset;
10273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deUint8*		dstPtr			= (deUint8*)dstBasePtr + dstOffset;
10283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps);
10303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
10343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::InternalError("Unsupported type");
10353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10373c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
10383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (varType.isBasicType())
10403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		basicType		= varType.getBasicType();
10423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				isMatrix		= glu::isDataTypeMatrix(basicType);
10433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
10443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				numVecs			= isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
10453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				numComps		= scalarSize / numVecs;
10463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		srcOffset		= layout.offset + layout.stride*elemNdx + (isMatrix ? layout.matrixStride*vecNdx : 0);
10523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		dstOffset		= sizeof(deUint32)*(elemNdx*scalarSize + vecNdx*numComps);
10533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint8*	srcPtr			= (const deUint8*)srcBasePtr + srcOffset;
10543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deUint8*		dstPtr			= (deUint8*)dstBasePtr + dstOffset;
10553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				deMemcpy(dstPtr, srcPtr, sizeof(deUint32)*numComps);
10573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::InternalError("Unsupported type");
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::uploadInputBuffer (const void* const* inputPtrs, int numValues)
10653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl				= m_renderCtx.getFunctions();
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			buffer			= *m_inputBuffer;
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			inputStride		= getLayoutStride(m_inputLayout);
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				inputBufferSize	= inputStride*numValues;
10703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (inputBufferSize == 0)
10723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return; // No inputs
10733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
10753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, inputBufferSize, GL_MAP_WRITE_BIT);
10763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
10773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(mapPtr);
10783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_inputs.size() == m_inputLayout.size());
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (size_t inputNdx = 0; inputNdx < m_inputs.size(); ++inputNdx)
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType&		varType		= m_inputs[inputNdx].varType;
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const VarLayout&		layout		= m_inputLayout[inputNdx];
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], mapPtr);
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (...)
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw;
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
10973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
10983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
10993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11003c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::readOutputBuffer (void* const* outputPtrs, int numValues)
11013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl					= m_renderCtx.getFunctions();
11033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			buffer				= *m_outputBuffer;
11043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			outputStride		= getLayoutStride(m_outputLayout);
11053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				outputBufferSize	= numValues*outputStride;
11063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(outputBufferSize > 0); // At least some outputs are required.
11083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
11103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void* mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, outputBufferSize, GL_MAP_READ_BIT);
11113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
11123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(mapPtr);
11133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	try
11153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(m_outputs.size() == m_outputLayout.size());
11173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (size_t outputNdx = 0; outputNdx < m_outputs.size(); ++outputNdx)
11183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::VarType&		varType		= m_outputs[outputNdx].varType;
11203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const VarLayout&		layout		= m_outputLayout[outputNdx];
11213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			copyFromBuffer(varType, layout, numValues, mapPtr, outputPtrs[outputNdx]);
11233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	catch (...)
11263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
11283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw;
11293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
11323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
11333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
11343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11353c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::declareBufferBlocks (std::ostream& src, const ShaderSpec& spec)
11363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Input struct
11383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!spec.inputs.empty())
11393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::StructType inputStruct("Inputs");
11413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
11423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			inputStruct.addMember(symIter->name.c_str(), symIter->varType);
11433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << glu::declare(&inputStruct) << ";\n";
11443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Output struct
11473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::StructType outputStruct("Outputs");
11493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
11503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			outputStruct.addMember(symIter->name.c_str(), symIter->varType);
11513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << glu::declare(&outputStruct) << ";\n";
11523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n";
11553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!spec.inputs.empty())
11573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src	<< "layout(binding = " << int(INPUT_BUFFER_BINDING) << ", std430) buffer InBuffer\n"
11593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "{\n"
11603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "	Inputs inputs[];\n"
11613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			<< "};\n";
11623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src	<< "layout(binding = " << int(OUTPUT_BUFFER_BINDING) << ", std430) buffer OutBuffer\n"
11653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
11663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	Outputs outputs[];\n"
11673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "};\n"
11683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n";
11693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
11703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11713c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid BufferIoExecutor::generateExecBufferIo (std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName)
11723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
11743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]." << symIter->name << ";\n";
11753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
11773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n";
11783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n";
11803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::istringstream	opSrc	(spec.source);
11833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		std::string			line;
11843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (std::getline(opSrc, line))
11863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			src << "\t" << line << "\n";
11873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n";
11903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
11913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n";
11923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
11933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// ComputeShaderExecutor
11953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11963c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ComputeShaderExecutor : public BufferIoExecutor
11973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11983c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
11993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						ComputeShaderExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
12003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						~ComputeShaderExecutor	(void);
12013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				execute					(int numValues, const void* const* inputs, void* const* outputs);
12033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12043c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
12053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static std::string	generateComputeShader	(const ShaderSpec& spec);
12063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::IVec3			m_maxWorkSize;
12083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
12093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12103c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::string ComputeShaderExecutor::generateComputeShader (const ShaderSpec& spec)
12113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
12133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(spec.version) << "\n";
12153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!spec.globalDeclarations.empty())
12173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << spec.globalDeclarations << "\n";
12183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "layout(local_size_x = 1) in;\n"
12203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\n";
12213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	declareBufferBlocks(src, spec);
12233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n"
12253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "{\n"
12263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n"
12273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	                   + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n";
12283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	generateExecBufferIo(src, spec, "invocationNdx");
12303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
12323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
12343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12363c827367444ee418f129b2c238299f49d3264554Jarkko PoyryComputeShaderExecutor::ComputeShaderExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
12373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: BufferIoExecutor	(renderCtx, shaderSpec,
12383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						 glu::ProgramSources() << glu::ComputeSource(generateComputeShader(shaderSpec)))
12393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_maxWorkSize	= tcu::IVec3(128,128,64); // Minimum in 3plus
12413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12433c827367444ee418f129b2c238299f49d3264554Jarkko PoyryComputeShaderExecutor::~ComputeShaderExecutor (void)
12443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12473c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ComputeShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
12483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl						= m_renderCtx.getFunctions();
12503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				maxValuesPerInvocation	= m_maxWorkSize[0];
12513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			inputStride				= getInputStride();
12523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32			outputStride			= getOutputStride();
12533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	initBuffers(numValues);
12553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup input buffer & copy data
12573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	uploadInputBuffer(inputs, numValues);
12583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Perform compute invocations
12603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int curOffset = 0;
12623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		while (curOffset < numValues)
12633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset);
12653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (inputStride > 0)
12673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer(), curOffset*inputStride, numToExec*inputStride);
12683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer(), curOffset*outputStride, numToExec*outputStride);
12703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_SHADER_STORAGE_BUFFER)");
12713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			gl.dispatchCompute(numToExec, 1, 1);
12733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()");
12743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			curOffset += numToExec;
12763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back data
12803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	readOutputBuffer(outputs, numValues);
12813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Tessellation utils
12843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12853c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateVertexShaderForTess (glu::GLSLVersion version)
12863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	src;
12883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(version) << "\n";
12903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n{\n"
12923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "	gl_Position = vec4(gl_VertexID/2, gl_VertexID%2, 0.0, 1.0);\n"
12933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "}\n";
12943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
12963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
12973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12988852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyryclass CheckTessSupport
12998852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry{
13008852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyrypublic:
1301582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	enum Stage
1302582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	{
1303582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		STAGE_CONTROL = 0,
1304582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		STAGE_EVAL,
1305582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	};
1306582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
1307582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	inline CheckTessSupport (const glu::RenderContext& renderCtx, Stage stage)
13088852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	{
1309582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		const int numBlockRequired = 2; // highest binding is always 1 (output) i.e. count == 2
1310582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
13118852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		if (renderCtx.getType().getAPI().getProfile() == glu::PROFILE_ES)
13128852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			checkExtension(renderCtx, "GL_EXT_tessellation_shader");
1313582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry
1314582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		if (stage == STAGE_CONTROL)
1315582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry			checkLimit(renderCtx, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, numBlockRequired);
1316582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		else if (stage == STAGE_EVAL)
1317582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry			checkLimit(renderCtx, GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, numBlockRequired);
1318582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry		else
1319582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry			DE_ASSERT(false);
13208852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	}
13218852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry};
13228852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry
13233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TessControlExecutor
13243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13258852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyryclass TessControlExecutor : private CheckTessSupport, public BufferIoExecutor
13263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13273c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
13283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						TessControlExecutor			(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
13293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						~TessControlExecutor		(void);
13303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				execute						(int numValues, const void* const* inputs, void* const* outputs);
13323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
13343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static std::string	generateTessControlShader	(const ShaderSpec& shaderSpec);
13353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
13363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13373c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::string TessControlExecutor::generateTessControlShader (const ShaderSpec& shaderSpec)
13383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
13403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
13423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (shaderSpec.version == glu::GLSL_VERSION_310_ES)
13443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "#extension GL_EXT_tessellation_shader : require\n";
13453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!shaderSpec.globalDeclarations.empty())
13473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << shaderSpec.globalDeclarations << "\n";
13483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\nlayout(vertices = 1) out;\n\n";
13503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	declareBufferBlocks(src, shaderSpec);
13523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n{\n";
13543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < 2; ndx++)
13563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
13573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < 4; ndx++)
13593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
13603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n"
13623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\thighp uint invocationId = uint(gl_PrimitiveID);\n";
13633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	generateExecBufferIo(src, shaderSpec, "invocationId");
13653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
13673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
13693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
13703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13713c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generateEmptyTessEvalShader (glu::GLSLVersion version)
13723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
13743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(version) << "\n";
13763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (version == glu::GLSL_VERSION_310_ES)
13783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "#extension GL_EXT_tessellation_shader : require\n\n";
13793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "layout(triangles, ccw) in;\n";
13813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\nvoid main (void)\n{\n"
13833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\tgl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
13843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "}\n";
13853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
13873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
13883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13893c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTessControlExecutor::TessControlExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1390582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	: CheckTessSupport	(renderCtx, STAGE_CONTROL)
13918852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	, BufferIoExecutor	(renderCtx, shaderSpec, glu::ProgramSources()
13923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
13933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::TessellationControlSource(generateTessControlShader(shaderSpec))
13943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::TessellationEvaluationSource(generateEmptyTessEvalShader(shaderSpec.version))
13953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
13963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
13983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13993c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTessControlExecutor::~TessControlExecutor (void)
14003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
14023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14033c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TessControlExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
14043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl	= m_renderCtx.getFunctions();
14063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	initBuffers(numValues);
14083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup input buffer & copy data
14103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	uploadInputBuffer(inputs, numValues);
14113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_inputs.empty())
14133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
14143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
14163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Render patches
14183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.patchParameteri(GL_PATCH_VERTICES, 3);
14193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.drawArrays(GL_PATCHES, 0, 3*numValues);
14203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back data
14223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	readOutputBuffer(outputs, numValues);
14233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
14243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// TessEvaluationExecutor
14263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14278852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyryclass TessEvaluationExecutor : private CheckTessSupport, public BufferIoExecutor
14283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14293c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
14303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						TessEvaluationExecutor	(const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec);
14313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						~TessEvaluationExecutor	(void);
14323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void				execute					(int numValues, const void* const* inputs, void* const* outputs);
14343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14353c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
14363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static std::string	generateTessEvalShader	(const ShaderSpec& shaderSpec);
14373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
14383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14393c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string generatePassthroughTessControlShader (glu::GLSLVersion version)
14403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
14423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(version) << "\n";
14443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (version == glu::GLSL_VERSION_310_ES)
14463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "#extension GL_EXT_tessellation_shader : require\n\n";
14473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "layout(vertices = 1) out;\n\n";
14493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n{\n";
14513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < 2; ndx++)
14533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
14543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < 4; ndx++)
14563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
14573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "}\n";
14593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
14613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
14623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::string TessEvaluationExecutor::generateTessEvalShader (const ShaderSpec& shaderSpec)
14643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream src;
14663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
14683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (shaderSpec.version == glu::GLSL_VERSION_310_ES)
14703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << "#extension GL_EXT_tessellation_shader : require\n";
14713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!shaderSpec.globalDeclarations.empty())
14733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		src << shaderSpec.globalDeclarations << "\n";
14743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "\n";
14763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "layout(isolines, equal_spacing) in;\n\n";
14783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	declareBufferBlocks(src, shaderSpec);
14803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src << "void main (void)\n{\n"
14823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "\tgl_Position = vec4(gl_TessCoord.x, 0.0, 0.0, 1.0);\n"
1483a2d25ce999fbbe13789e80ce803cc7b96d2a4c9dPyry Haulos		<< "\thighp uint invocationId = uint(gl_PrimitiveID)*2u + (gl_TessCoord.x > 0.5 ? 1u : 0u);\n";
14843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	generateExecBufferIo(src, shaderSpec, "invocationId");
14863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	src	<< "}\n";
14883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return src.str();
14903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
14913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14923c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTessEvaluationExecutor::TessEvaluationExecutor (const glu::RenderContext& renderCtx, const ShaderSpec& shaderSpec)
1493582ae6e4b619cd8255b95447a3475070fff1b6b4Jarkko Pöyry	: CheckTessSupport	(renderCtx, STAGE_EVAL)
14948852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry	, BufferIoExecutor	(renderCtx, shaderSpec, glu::ProgramSources()
14953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
14963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::TessellationControlSource(generatePassthroughTessControlShader(shaderSpec.version))
14973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::TessellationEvaluationSource(generateTessEvalShader(shaderSpec))
14983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
14993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
15013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15023c827367444ee418f129b2c238299f49d3264554Jarkko PoyryTessEvaluationExecutor::~TessEvaluationExecutor (void)
15033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
15053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15063c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TessEvaluationExecutor::execute (int numValues, const void* const* inputs, void* const* outputs)
15073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glw::Functions&	gl				= m_renderCtx.getFunctions();
15093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				alignedValues	= deAlign32(numValues, 2);
15103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Initialize buffers with aligned value count to make room for padding
15123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	initBuffers(alignedValues);
15133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Setup input buffer & copy data
15153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	uploadInputBuffer(inputs, numValues);
15163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \todo [2014-06-26 pyry] Duplicate last value in the buffer to prevent infinite loops for example?
15183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_inputs.empty())
15203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
15213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
15233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Render patches
15253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	gl.patchParameteri(GL_PATCH_VERTICES, 2);
1526a2d25ce999fbbe13789e80ce803cc7b96d2a4c9dPyry Haulos	gl.drawArrays(GL_PATCHES, 0, alignedValues);
15273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Read back data
15293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	readOutputBuffer(outputs, numValues);
15303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
15313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Utilities
15333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15343c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderExecutor* createExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const ShaderSpec& shaderSpec)
15353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (shaderType)
15373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_VERTEX:					return new VertexShaderExecutor		(renderCtx, shaderSpec);
15393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_TESSELLATION_CONTROL:		return new TessControlExecutor		(renderCtx, shaderSpec);
15403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_TESSELLATION_EVALUATION:	return new TessEvaluationExecutor	(renderCtx, shaderSpec);
15413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_GEOMETRY:					return new GeometryShaderExecutor	(renderCtx, shaderSpec);
15423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_FRAGMENT:					return new FragmentShaderExecutor	(renderCtx, shaderSpec);
15433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case glu::SHADERTYPE_COMPUTE:					return new ComputeShaderExecutor	(renderCtx, shaderSpec);
15443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		default:
15453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::InternalError("Unsupported shader type");
15463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
15473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
15483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // ShaderExecUtil
15503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // gls
15513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // deqp
1552