1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief sglr-rsg adaptation.
22 *//*--------------------------------------------------------------------*/
23
24#include "glsRandomShaderProgram.hpp"
25#include "rsgShader.hpp"
26
27namespace deqp
28{
29namespace gls
30{
31
32using std::vector;
33
34static rr::GenericVecType mapToGenericVecType (const rsg::VariableType& varType)
35{
36	if (varType.isFloatOrVec())
37		return rr::GENERICVECTYPE_FLOAT;
38	else if (varType.isIntOrVec())
39		return rr::GENERICVECTYPE_INT32;
40	else
41	{
42		DE_ASSERT(false);
43		return rr::GENERICVECTYPE_LAST;
44	}
45}
46
47static glu::DataType mapToBasicType (const rsg::VariableType& varType)
48{
49	if (varType.isFloatOrVec() || varType.isIntOrVec() || varType.isBoolOrVec())
50	{
51		const glu::DataType		scalarType		= varType.isFloatOrVec()	? glu::TYPE_FLOAT	:
52												  varType.isIntOrVec()		? glu::TYPE_INT		:
53												  varType.isBoolOrVec()		? glu::TYPE_BOOL	: glu::TYPE_LAST;
54		const int				numComps		= varType.getNumElements();
55
56		DE_ASSERT(de::inRange(numComps, 1, 4));
57		return glu::DataType(scalarType + numComps - 1);
58	}
59	else if (varType.getBaseType() == rsg::VariableType::TYPE_SAMPLER_2D)
60		return glu::TYPE_SAMPLER_2D;
61	else if (varType.getBaseType() == rsg::VariableType::TYPE_SAMPLER_CUBE)
62		return glu::TYPE_SAMPLER_CUBE;
63	else
64	{
65		DE_ASSERT(false);
66		return glu::TYPE_LAST;
67	}
68}
69
70static void generateProgramDeclaration (sglr::pdec::ShaderProgramDeclaration& decl, const rsg::Shader& vertexShader, const rsg::Shader& fragmentShader, int numUnifiedUniforms, const rsg::ShaderInput* const* unifiedUniforms)
71{
72	decl << sglr::pdec::VertexSource(vertexShader.getSource())
73		 << sglr::pdec::FragmentSource(fragmentShader.getSource());
74
75	for (vector<rsg::ShaderInput*>::const_iterator vtxInIter = vertexShader.getInputs().begin(); vtxInIter != vertexShader.getInputs().end(); ++vtxInIter)
76	{
77		const rsg::ShaderInput*	vertexInput	= *vtxInIter;
78		decl << sglr::pdec::VertexAttribute(vertexInput->getVariable()->getName(), mapToGenericVecType(vertexInput->getVariable()->getType()));
79	}
80
81	for (vector<rsg::ShaderInput*>::const_iterator fragInIter = fragmentShader.getInputs().begin(); fragInIter != fragmentShader.getInputs().end(); ++fragInIter)
82	{
83		const rsg::ShaderInput*	fragInput	= *fragInIter;
84		decl << sglr::pdec::VertexToFragmentVarying(mapToGenericVecType(fragInput->getVariable()->getType()));
85	}
86
87	for (int uniformNdx = 0; uniformNdx < numUnifiedUniforms; uniformNdx++)
88	{
89		const rsg::ShaderInput*	uniform	= unifiedUniforms[uniformNdx];
90		decl << sglr::pdec::Uniform(uniform->getVariable()->getName(), mapToBasicType(uniform->getVariable()->getType()));
91	}
92
93	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
94}
95
96static sglr::pdec::ShaderProgramDeclaration generateProgramDeclaration (const rsg::Shader& vertexShader, const rsg::Shader& fragmentShader, int numUnifiedUniforms, const rsg::ShaderInput* const* unifiedUniforms)
97{
98	sglr::pdec::ShaderProgramDeclaration decl;
99	generateProgramDeclaration(decl, vertexShader, fragmentShader, numUnifiedUniforms, unifiedUniforms);
100	return decl;
101}
102
103static const rsg::Variable* findShaderOutputByName (const rsg::Shader& shader, const char* name)
104{
105	vector<const rsg::Variable*> outputs;
106	shader.getOutputs(outputs);
107
108	for (vector<const rsg::Variable*>::const_iterator iter = outputs.begin(); iter != outputs.end(); ++iter)
109	{
110		if (deStringEqual((*iter)->getName(), name))
111			return *iter;
112	}
113
114	return DE_NULL;
115}
116
117static const rsg::Variable* findShaderOutputByLocation (const rsg::Shader& shader, int location)
118{
119	vector<const rsg::Variable*> outputs;
120	shader.getOutputs(outputs);
121
122	for (vector<const rsg::Variable*>::const_iterator iter = outputs.begin(); iter != outputs.end(); iter++)
123	{
124		if ((*iter)->getLayoutLocation() == location)
125			return *iter;
126	}
127
128	return DE_NULL;
129}
130
131RandomShaderProgram::RandomShaderProgram (const rsg::Shader& vertexShader, const rsg::Shader& fragmentShader, int numUnifiedUniforms, const rsg::ShaderInput* const* unifiedUniforms)
132	: sglr::ShaderProgram	(generateProgramDeclaration(vertexShader, fragmentShader, numUnifiedUniforms, unifiedUniforms))
133	, m_vertexShader		(vertexShader)
134	, m_fragmentShader		(fragmentShader)
135	, m_numUnifiedUniforms	(numUnifiedUniforms)
136	, m_unifiedUniforms		(unifiedUniforms)
137	, m_positionVar			(findShaderOutputByName(vertexShader, "gl_Position"))
138	, m_fragColorVar		(findShaderOutputByLocation(fragmentShader, 0))
139	, m_execCtx				(m_sampler2DMap, m_samplerCubeMap)
140{
141	TCU_CHECK_INTERNAL(m_positionVar && m_positionVar->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT && m_positionVar->getType().getNumElements() == 4);
142	TCU_CHECK_INTERNAL(m_fragColorVar && m_fragColorVar->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT && m_fragColorVar->getType().getNumElements() == 4);
143
144	// Build list of vertex outputs.
145	for (vector<rsg::ShaderInput*>::const_iterator fragInIter = fragmentShader.getInputs().begin(); fragInIter != fragmentShader.getInputs().end(); ++fragInIter)
146	{
147		const rsg::ShaderInput*	fragInput		= *fragInIter;
148		const rsg::Variable*	vertexOutput	= findShaderOutputByName(vertexShader, fragInput->getVariable()->getName());
149
150		TCU_CHECK_INTERNAL(vertexOutput);
151		m_vertexOutputs.push_back(vertexOutput);
152	}
153}
154
155void RandomShaderProgram::refreshUniforms (void) const
156{
157	DE_ASSERT(m_numUnifiedUniforms == (int)m_uniforms.size());
158
159	for (int uniformNdx = 0; uniformNdx < m_numUnifiedUniforms; uniformNdx++)
160	{
161		const rsg::Variable*		uniformVar	= m_unifiedUniforms[uniformNdx]->getVariable();
162		const rsg::VariableType&	uniformType	= uniformVar->getType();
163		const sglr::UniformSlot&	uniformSlot	= m_uniforms[uniformNdx];
164
165		m_execCtx.getValue(uniformVar) = rsg::ConstValueAccess(uniformType, (const rsg::Scalar*)&uniformSlot.value).value();
166	}
167}
168
169void RandomShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
170{
171	// \todo [2013-12-13 pyry] Do only when necessary.
172	refreshUniforms();
173
174	int packetOffset = 0;
175
176	while (packetOffset < numPackets)
177	{
178		const int	numToExecute	= de::min(numPackets-packetOffset, (int)rsg::EXEC_VEC_WIDTH);
179
180		// Fetch attributes.
181		for (int attribNdx = 0; attribNdx < (int)m_vertexShader.getInputs().size(); ++attribNdx)
182		{
183			const rsg::Variable*		attribVar		= m_vertexShader.getInputs()[attribNdx]->getVariable();
184			const rsg::VariableType&	attribType		= attribVar->getType();
185			const int					numComponents	= attribType.getNumElements();
186			rsg::ExecValueAccess		access			= m_execCtx.getValue(attribVar);
187
188			DE_ASSERT(attribType.isFloatOrVec() && de::inRange(numComponents, 1, 4));
189
190			for (int ndx = 0; ndx < numToExecute; ndx++)
191			{
192				const int				packetNdx	= ndx+packetOffset;
193				const rr::VertexPacket*	packet		= packets[packetNdx];
194				const tcu::Vec4			attribValue	= rr::readVertexAttribFloat(inputs[attribNdx], packet->instanceNdx, packet->vertexNdx);
195
196										access.component(0).asFloat(ndx) = attribValue[0];
197				if (numComponents >= 2)	access.component(1).asFloat(ndx) = attribValue[1];
198				if (numComponents >= 3)	access.component(2).asFloat(ndx) = attribValue[2];
199				if (numComponents >= 4)	access.component(3).asFloat(ndx) = attribValue[3];
200			}
201		}
202
203		m_vertexShader.execute(m_execCtx);
204
205		// Store position
206		{
207			const rsg::ExecConstValueAccess	access	= m_execCtx.getValue(m_positionVar);
208
209			for (int ndx = 0; ndx < numToExecute; ndx++)
210			{
211				const int			packetNdx	= ndx+packetOffset;
212				rr::VertexPacket*	packet		= packets[packetNdx];
213
214				packet->position[0] = access.component(0).asFloat(ndx);
215				packet->position[1] = access.component(1).asFloat(ndx);
216				packet->position[2] = access.component(2).asFloat(ndx);
217				packet->position[3] = access.component(3).asFloat(ndx);
218			}
219		}
220
221		// Other varyings
222		for (int varNdx = 0; varNdx < (int)m_vertexOutputs.size(); varNdx++)
223		{
224			const rsg::Variable*			var				= m_vertexOutputs[varNdx];
225			const rsg::VariableType&		varType			= var->getType();
226			const int						numComponents	= varType.getNumElements();
227			const rsg::ExecConstValueAccess	access			= m_execCtx.getValue(var);
228
229			DE_ASSERT(varType.isFloatOrVec() && de::inRange(numComponents, 1, 4));
230
231			for (int ndx = 0; ndx < numToExecute; ndx++)
232			{
233				const int				packetNdx	= ndx+packetOffset;
234				rr::VertexPacket* const	packet		= packets[packetNdx];
235				float* const			dst			= packet->outputs[varNdx].getAccess<float>();
236
237										dst[0] = access.component(0).asFloat(ndx);
238				if (numComponents >= 2) dst[1] = access.component(1).asFloat(ndx);
239				if (numComponents >= 3) dst[2] = access.component(2).asFloat(ndx);
240				if (numComponents >= 4) dst[3] = access.component(3).asFloat(ndx);
241			}
242		}
243
244		packetOffset += numToExecute;
245	}
246}
247
248void RandomShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
249{
250	const rsg::ExecConstValueAccess	fragColorAccess	= m_execCtx.getValue(m_fragColorVar);
251	int								packetOffset	= 0;
252
253	DE_STATIC_ASSERT(rsg::EXEC_VEC_WIDTH % rr::NUM_FRAGMENTS_PER_PACKET == 0);
254
255	while (packetOffset < numPackets)
256	{
257		const int	numPacketsToExecute	= de::min(numPackets-packetOffset, (int)rsg::EXEC_VEC_WIDTH / (int)rr::NUM_FRAGMENTS_PER_PACKET);
258
259		// Interpolate varyings.
260		for (int varNdx = 0; varNdx < (int)m_fragmentShader.getInputs().size(); ++varNdx)
261		{
262			const rsg::Variable*		var				= m_fragmentShader.getInputs()[varNdx]->getVariable();
263			const rsg::VariableType&	varType			= var->getType();
264			const int					numComponents	= varType.getNumElements();
265			rsg::ExecValueAccess		access			= m_execCtx.getValue(var);
266
267			DE_ASSERT(varType.isFloatOrVec() && de::inRange(numComponents, 1, 4));
268
269			for (int packetNdx = 0; packetNdx < numPacketsToExecute; packetNdx++)
270			{
271				const rr::FragmentPacket&	packet		= packets[packetOffset+packetNdx];
272
273				for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; fragNdx++)
274				{
275					const tcu::Vec4		varValue	= rr::readVarying<float>(packet, context, varNdx, fragNdx);
276					const int			dstNdx		= packetNdx*rr::NUM_FRAGMENTS_PER_PACKET + fragNdx;
277
278											access.component(0).asFloat(dstNdx) = varValue[0];
279					if (numComponents >= 2)	access.component(1).asFloat(dstNdx) = varValue[1];
280					if (numComponents >= 3)	access.component(2).asFloat(dstNdx) = varValue[2];
281					if (numComponents >= 4)	access.component(3).asFloat(dstNdx) = varValue[3];
282				}
283			}
284		}
285
286		m_fragmentShader.execute(m_execCtx);
287
288		// Store color
289		for (int packetNdx = 0; packetNdx < numPacketsToExecute; packetNdx++)
290		{
291			for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; fragNdx++)
292			{
293				const int		srcNdx	= packetNdx*rr::NUM_FRAGMENTS_PER_PACKET + fragNdx;
294				const tcu::Vec4 color	(fragColorAccess.component(0).asFloat(srcNdx),
295										 fragColorAccess.component(1).asFloat(srcNdx),
296										 fragColorAccess.component(2).asFloat(srcNdx),
297										 fragColorAccess.component(3).asFloat(srcNdx));
298
299				rr::writeFragmentOutput(context, packetOffset+packetNdx, fragNdx, 0, color);
300			}
301		}
302
303		packetOffset += numPacketsToExecute;
304	}
305}
306
307} // gls
308} // deqp
309