• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Random Shader Generator
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 Program Executor.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "rsgProgramExecutor.hpp"
25 #include "rsgExecutionContext.hpp"
26 #include "rsgVariableValue.hpp"
27 #include "rsgUtils.hpp"
28 #include "tcuSurface.hpp"
29 #include "deMath.h"
30 #include "deString.h"
31 
32 #include <set>
33 #include <string>
34 #include <map>
35 
36 using std::set;
37 using std::string;
38 using std::vector;
39 using std::map;
40 
41 namespace rsg
42 {
43 
44 class VaryingStorage
45 {
46 public:
47 							VaryingStorage		(const VariableType& type, int numVertices);
~VaryingStorage(void)48 							~VaryingStorage		(void) {}
49 
50 	ValueAccess				getValue			(const VariableType& type, int vtxNdx);
51 	ConstValueAccess		getValue			(const VariableType& type, int vtxNdx) const;
52 
53 private:
54 	std::vector<Scalar>		m_value;
55 };
56 
VaryingStorage(const VariableType & type,int numVertices)57 VaryingStorage::VaryingStorage (const VariableType& type, int numVertices)
58 	: m_value(type.getScalarSize()*numVertices)
59 {
60 }
61 
getValue(const VariableType & type,int vtxNdx)62 ValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx)
63 {
64 	return ValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
65 }
66 
getValue(const VariableType & type,int vtxNdx) const67 ConstValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx) const
68 {
69 	return ConstValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
70 }
71 
72 class VaryingStore
73 {
74 public:
75 							VaryingStore		(int numVertices);
76 							~VaryingStore		(void);
77 
78 	VaryingStorage*			getStorage			(const VariableType& type, const char* name);
79 
80 private:
81 	int											m_numVertices;
82 	std::map<std::string, VaryingStorage*>		m_values;
83 };
84 
VaryingStore(int numVertices)85 VaryingStore::VaryingStore (int numVertices)
86 	: m_numVertices(numVertices)
87 {
88 }
89 
~VaryingStore(void)90 VaryingStore::~VaryingStore (void)
91 {
92 	for (map<string, VaryingStorage*>::iterator i = m_values.begin(); i != m_values.end(); i++)
93 		delete i->second;
94 	m_values.clear();
95 }
96 
getStorage(const VariableType & type,const char * name)97 VaryingStorage* VaryingStore::getStorage (const VariableType& type, const char* name)
98 {
99 	VaryingStorage* storage = m_values[name];
100 
101 	if (!storage)
102 	{
103 		storage = new VaryingStorage(type, m_numVertices);
104 		m_values[name] = storage;
105 	}
106 
107 	return storage;
108 }
109 
interpolateVertexQuad(const tcu::Vec4 & quad,float x,float y)110 inline float interpolateVertexQuad (const tcu::Vec4& quad, float x, float y)
111 {
112 	float w00 = (1.0f-x)*(1.0f-y);
113 	float w01 = (1.0f-x)*y;
114 	float w10 = x*(1.0f-y);
115 	float w11 = x*y;
116 	return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
117 }
118 
interpolateVertex(float x0y0,float x1y1,float x,float y)119 inline float interpolateVertex (float x0y0, float x1y1, float x, float y)
120 {
121 	return interpolateVertexQuad(tcu::Vec4(x0y0, (x0y0+x1y1)*0.5f, (x0y0+x1y1)*0.5f, x1y1), x, y);
122 }
123 
interpolateTri(float v0,float v1,float v2,float x,float y)124 inline float interpolateTri (float v0, float v1, float v2, float x, float y)
125 {
126 	return v0 + (v1-v0)*x + (v2-v0)*y;
127 }
128 
interpolateFragment(const tcu::Vec4 & quad,float x,float y)129 inline float interpolateFragment (const tcu::Vec4& quad, float x, float y)
130 {
131 	if (x + y < 1.0f)
132 		return interpolateTri(quad.x(), quad.y(), quad.z(), x, y);
133 	else
134 		return interpolateTri(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
135 }
136 
137 template <int Stride>
interpolateVertexInput(StridedValueAccess<Stride> dst,int dstComp,const ConstValueRangeAccess valueRange,float x,float y)138 void interpolateVertexInput (StridedValueAccess<Stride> dst, int dstComp, const ConstValueRangeAccess valueRange, float x, float y)
139 {
140 	TCU_CHECK(valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT);
141 	int numElements = valueRange.getType().getNumElements();
142 	for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
143 	{
144 		float xd, yd;
145 		getVertexInterpolationCoords(xd, yd, x, y, elementNdx);
146 		dst.component(elementNdx).asFloat(dstComp) = interpolateVertex(valueRange.getMin().component(elementNdx).asFloat(), valueRange.getMax().component(elementNdx).asFloat(), xd, yd);
147 	}
148 }
149 
150 template <int Stride>
interpolateFragmentInput(StridedValueAccess<Stride> dst,int dstComp,ConstValueAccess vtx0,ConstValueAccess vtx1,ConstValueAccess vtx2,ConstValueAccess vtx3,float x,float y)151 void interpolateFragmentInput (StridedValueAccess<Stride> dst, int dstComp, ConstValueAccess vtx0, ConstValueAccess vtx1, ConstValueAccess vtx2, ConstValueAccess vtx3, float x, float y)
152 {
153 	TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
154 	int numElements = dst.getType().getNumElements();
155 	for (int ndx = 0; ndx < numElements; ndx++)
156 		dst.component(ndx).asFloat(dstComp) = interpolateFragment(tcu::Vec4(vtx0.component(ndx).asFloat(), vtx1.component(ndx).asFloat(), vtx2.component(ndx).asFloat(), vtx3.component(ndx).asFloat()), x, y);
157 }
158 
159 template <int Stride>
copyVarying(ValueAccess dst,ConstStridedValueAccess<Stride> src,int compNdx)160 void copyVarying (ValueAccess dst, ConstStridedValueAccess<Stride> src, int compNdx)
161 {
162 	TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
163 	for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
164 		dst.component(elemNdx).asFloat() = src.component(elemNdx).asFloat(compNdx);
165 }
166 
ProgramExecutor(const tcu::PixelBufferAccess & dst,int gridWidth,int gridHeight)167 ProgramExecutor::ProgramExecutor (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight)
168 	: m_dst			(dst)
169 	, m_gridWidth	(gridWidth)
170 	, m_gridHeight	(gridHeight)
171 {
172 }
173 
~ProgramExecutor(void)174 ProgramExecutor::~ProgramExecutor (void)
175 {
176 }
177 
setTexture(int samplerNdx,const tcu::Texture2D * texture,const tcu::Sampler & sampler)178 void ProgramExecutor::setTexture (int samplerNdx, const tcu::Texture2D* texture, const tcu::Sampler& sampler)
179 {
180 	m_samplers2D[samplerNdx] = Sampler2D(texture, sampler);
181 }
182 
setTexture(int samplerNdx,const tcu::TextureCube * texture,const tcu::Sampler & sampler)183 void ProgramExecutor::setTexture (int samplerNdx, const tcu::TextureCube* texture, const tcu::Sampler& sampler)
184 {
185 	m_samplersCube[samplerNdx] = SamplerCube(texture, sampler);
186 }
187 
computeVertexIndices(float cellWidth,float cellHeight,int gridVtxWidth,int gridVtxHeight,int x,int y)188 inline tcu::IVec4 computeVertexIndices (float cellWidth, float cellHeight, int gridVtxWidth, int gridVtxHeight, int x, int y)
189 {
190 	DE_UNREF(gridVtxHeight);
191 	int x0 = (int)deFloatFloor((float)x / cellWidth);
192 	int y0 = (int)deFloatFloor((float)y / cellHeight);
193 	return tcu::IVec4(y0*gridVtxWidth + x0, y0*gridVtxWidth + x0 + 1, (y0+1)*gridVtxWidth + x0, (y0+1)*gridVtxWidth + x0 + 1);
194 }
195 
computeGridCellWeights(float cellWidth,float cellHeight,int x,int y)196 inline tcu::Vec2 computeGridCellWeights (float cellWidth, float cellHeight, int x, int y)
197 {
198 	float gx = ((float)x + 0.5f) / cellWidth;
199 	float gy = ((float)y + 0.5f) / cellHeight;
200 	return tcu::Vec2(deFloatFrac(gx), deFloatFrac(gy));
201 }
202 
toColor(tcu::Vec4 rgba)203 inline tcu::RGBA toColor (tcu::Vec4 rgba)
204 {
205 	return tcu::RGBA(deClamp32(deRoundFloatToInt32(rgba.x()*255), 0, 255),
206 					 deClamp32(deRoundFloatToInt32(rgba.y()*255), 0, 255),
207 					 deClamp32(deRoundFloatToInt32(rgba.z()*255), 0, 255),
208 					 deClamp32(deRoundFloatToInt32(rgba.w()*255), 0, 255));
209 }
210 
execute(const Shader & vertexShader,const Shader & fragmentShader,const vector<VariableValue> & uniformValues)211 void ProgramExecutor::execute (const Shader& vertexShader, const Shader& fragmentShader, const vector<VariableValue>& uniformValues)
212 {
213 	int	gridVtxWidth	= m_gridWidth+1;
214 	int gridVtxHeight	= m_gridHeight+1;
215 	int numVertices		= gridVtxWidth*gridVtxHeight;
216 
217 	VaryingStore varyingStore(numVertices);
218 
219 	// Execute vertex shader
220 	{
221 		ExecutionContext	execCtx(m_samplers2D, m_samplersCube);
222 		int					numPackets	= numVertices + ((numVertices%EXEC_VEC_WIDTH) ? 1 : 0);
223 
224 		const vector<ShaderInput*>& inputs	= vertexShader.getInputs();
225 		vector<const Variable*>		outputs;
226 		vertexShader.getOutputs(outputs);
227 
228 		// Set uniform values
229 		for (vector<VariableValue>::const_iterator uniformIter = uniformValues.begin(); uniformIter != uniformValues.end(); uniformIter++)
230 			execCtx.getValue(uniformIter->getVariable()) = uniformIter->getValue().value();
231 
232 		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
233 		{
234 			int packetStart	= packetNdx*EXEC_VEC_WIDTH;
235 			int packetEnd	= deMin32((packetNdx+1)*EXEC_VEC_WIDTH, numVertices);
236 
237 			// Compute values for vertex shader inputs
238 			for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
239 			{
240 				const ShaderInput*	input	= *i;
241 				ExecValueAccess		access	= execCtx.getValue(input->getVariable());
242 
243 				for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
244 				{
245 					int		y	= (vtxNdx/gridVtxWidth);
246 					int		x	= vtxNdx - y*gridVtxWidth;
247 					float	xf	= (float)x / (float)(gridVtxWidth-1);
248 					float	yf	= (float)y / (float)(gridVtxHeight-1);
249 
250 					interpolateVertexInput(access, vtxNdx-packetStart, input->getValueRange(), xf, yf);
251 				}
252 			}
253 
254 			// Execute vertex shader for packet
255 			vertexShader.execute(execCtx);
256 
257 			// Store output values
258 			for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
259 			{
260 				const Variable*			output	= *i;
261 
262 				if (deStringEqual(output->getName(), "gl_Position"))
263 					continue; // Do not store position
264 
265 				ExecConstValueAccess	access	= execCtx.getValue(output);
266 				VaryingStorage*			dst		= varyingStore.getStorage(output->getType(), output->getName());
267 
268 				for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
269 				{
270 					ValueAccess varyingAccess = dst->getValue(output->getType(), vtxNdx);
271 					copyVarying(varyingAccess, access, vtxNdx-packetStart);
272 				}
273 			}
274 		}
275 	}
276 
277 	// Execute fragment shader
278 	{
279 		ExecutionContext execCtx(m_samplers2D, m_samplersCube);
280 
281 		// Assign uniform values
282 		for (vector<VariableValue>::const_iterator i = uniformValues.begin(); i != uniformValues.end(); i++)
283 			execCtx.getValue(i->getVariable()) = i->getValue().value();
284 
285 		const vector<ShaderInput*>& inputs			= fragmentShader.getInputs();
286 		const Variable*				fragColorVar	= DE_NULL;
287 		vector<const Variable*>		outputs;
288 
289 		// Find fragment shader output assigned to location 0. This is fragment color.
290 		fragmentShader.getOutputs(outputs);
291 		for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
292 		{
293 			if ((*i)->getLayoutLocation() == 0)
294 			{
295 				fragColorVar = *i;
296 				break;
297 			}
298 		}
299 		TCU_CHECK(fragColorVar);
300 
301 		int	width		= m_dst.getWidth();
302 		int height		= m_dst.getHeight();
303 		int numPackets	= (width*height)/EXEC_VEC_WIDTH + (((width*height)%EXEC_VEC_WIDTH) ? 1 : 0);
304 
305 		float cellWidth		= (float)width	/ (float)m_gridWidth;
306 		float cellHeight	= (float)height	/ (float)m_gridHeight;
307 
308 		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
309 		{
310 			int packetStart	= packetNdx*EXEC_VEC_WIDTH;
311 			int packetEnd	= deMin32((packetNdx+1)*EXEC_VEC_WIDTH, width*height);
312 
313 			// Interpolate varyings
314 			for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
315 			{
316 				const ShaderInput*		input	= *i;
317 				ExecValueAccess			access	= execCtx.getValue(input->getVariable());
318 				const VariableType&		type	= input->getVariable()->getType();
319 				const VaryingStorage*	src		= varyingStore.getStorage(type, input->getVariable()->getName());
320 
321 				// \todo [2011-03-08 pyry] Part of this could be pre-computed...
322 				for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
323 				{
324 					int y = fragNdx/width;
325 					int x = fragNdx - y*width;
326 					tcu::IVec4	vtxIndices	= computeVertexIndices(cellWidth, cellHeight, gridVtxWidth, gridVtxHeight, x, y);
327 					tcu::Vec2	weights		= computeGridCellWeights(cellWidth, cellHeight, x, y);
328 
329 					interpolateFragmentInput(access, fragNdx-packetStart,
330 											 src->getValue(type, vtxIndices.x()),
331 											 src->getValue(type, vtxIndices.y()),
332 											 src->getValue(type, vtxIndices.z()),
333 											 src->getValue(type, vtxIndices.w()),
334 											 weights.x(), weights.y());
335 				}
336 			}
337 
338 			// Execute fragment shader
339 			fragmentShader.execute(execCtx);
340 
341 			// Write resulting color
342 			ExecConstValueAccess colorValue = execCtx.getValue(fragColorVar);
343 			for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
344 			{
345 				int			y		= fragNdx/width;
346 				int			x		= fragNdx - y*width;
347 				int			cNdx	= fragNdx-packetStart;
348 				tcu::Vec4	c		= tcu::Vec4(colorValue.component(0).asFloat(cNdx),
349 												colorValue.component(1).asFloat(cNdx),
350 												colorValue.component(2).asFloat(cNdx),
351 												colorValue.component(3).asFloat(cNdx));
352 
353 				// \todo [2012-11-13 pyry] Reverse order.
354 				m_dst.setPixel(c, x, m_dst.getHeight()-y-1);
355 			}
356 		}
357 	}
358 }
359 
360 } // rsg
361