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::map;
37 using std::set;
38 using std::string;
39 using std::vector;
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 }
51
52 ValueAccess getValue(const VariableType &type, int vtxNdx);
53 ConstValueAccess getValue(const VariableType &type, int vtxNdx) const;
54
55 private:
56 std::vector<Scalar> m_value;
57 };
58
VaryingStorage(const VariableType & type,int numVertices)59 VaryingStorage::VaryingStorage(const VariableType &type, int numVertices) : m_value(type.getScalarSize() * numVertices)
60 {
61 }
62
getValue(const VariableType & type,int vtxNdx)63 ValueAccess VaryingStorage::getValue(const VariableType &type, int vtxNdx)
64 {
65 return ValueAccess(type, &m_value[type.getScalarSize() * vtxNdx]);
66 }
67
getValue(const VariableType & type,int vtxNdx) const68 ConstValueAccess VaryingStorage::getValue(const VariableType &type, int vtxNdx) const
69 {
70 return ConstValueAccess(type, &m_value[type.getScalarSize() * vtxNdx]);
71 }
72
73 class VaryingStore
74 {
75 public:
76 VaryingStore(int numVertices);
77 ~VaryingStore(void);
78
79 VaryingStorage *getStorage(const VariableType &type, const char *name);
80
81 private:
82 int m_numVertices;
83 std::map<std::string, VaryingStorage *> m_values;
84 };
85
VaryingStore(int numVertices)86 VaryingStore::VaryingStore(int numVertices) : 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,
139 float x, float y)
140 {
141 TCU_CHECK(valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT);
142 int numElements = valueRange.getType().getNumElements();
143 for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
144 {
145 float xd, yd;
146 getVertexInterpolationCoords(xd, yd, x, y, elementNdx);
147 dst.component(elementNdx).asFloat(dstComp) =
148 interpolateVertex(valueRange.getMin().component(elementNdx).asFloat(),
149 valueRange.getMax().component(elementNdx).asFloat(), xd, yd);
150 }
151 }
152
153 template <int Stride>
interpolateFragmentInput(StridedValueAccess<Stride> dst,int dstComp,ConstValueAccess vtx0,ConstValueAccess vtx1,ConstValueAccess vtx2,ConstValueAccess vtx3,float x,float y)154 void interpolateFragmentInput(StridedValueAccess<Stride> dst, int dstComp, ConstValueAccess vtx0, ConstValueAccess vtx1,
155 ConstValueAccess vtx2, ConstValueAccess vtx3, float x, float y)
156 {
157 TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
158 int numElements = dst.getType().getNumElements();
159 for (int ndx = 0; ndx < numElements; ndx++)
160 dst.component(ndx).asFloat(dstComp) =
161 interpolateFragment(tcu::Vec4(vtx0.component(ndx).asFloat(), vtx1.component(ndx).asFloat(),
162 vtx2.component(ndx).asFloat(), vtx3.component(ndx).asFloat()),
163 x, y);
164 }
165
166 template <int Stride>
copyVarying(ValueAccess dst,ConstStridedValueAccess<Stride> src,int compNdx)167 void copyVarying(ValueAccess dst, ConstStridedValueAccess<Stride> src, int compNdx)
168 {
169 TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT);
170 for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
171 dst.component(elemNdx).asFloat() = src.component(elemNdx).asFloat(compNdx);
172 }
173
ProgramExecutor(const tcu::PixelBufferAccess & dst,int gridWidth,int gridHeight)174 ProgramExecutor::ProgramExecutor(const tcu::PixelBufferAccess &dst, int gridWidth, int gridHeight)
175 : m_dst(dst)
176 , m_gridWidth(gridWidth)
177 , m_gridHeight(gridHeight)
178 {
179 }
180
~ProgramExecutor(void)181 ProgramExecutor::~ProgramExecutor(void)
182 {
183 }
184
setTexture(int samplerNdx,const tcu::Texture2D * texture,const tcu::Sampler & sampler)185 void ProgramExecutor::setTexture(int samplerNdx, const tcu::Texture2D *texture, const tcu::Sampler &sampler)
186 {
187 m_samplers2D[samplerNdx] = Sampler2D(texture, sampler);
188 }
189
setTexture(int samplerNdx,const tcu::TextureCube * texture,const tcu::Sampler & sampler)190 void ProgramExecutor::setTexture(int samplerNdx, const tcu::TextureCube *texture, const tcu::Sampler &sampler)
191 {
192 m_samplersCube[samplerNdx] = SamplerCube(texture, sampler);
193 }
194
computeVertexIndices(float cellWidth,float cellHeight,int gridVtxWidth,int gridVtxHeight,int x,int y)195 inline tcu::IVec4 computeVertexIndices(float cellWidth, float cellHeight, int gridVtxWidth, int gridVtxHeight, int x,
196 int y)
197 {
198 DE_UNREF(gridVtxHeight);
199 int x0 = (int)deFloatFloor((float)x / cellWidth);
200 int y0 = (int)deFloatFloor((float)y / cellHeight);
201 return tcu::IVec4(y0 * gridVtxWidth + x0, y0 * gridVtxWidth + x0 + 1, (y0 + 1) * gridVtxWidth + x0,
202 (y0 + 1) * gridVtxWidth + x0 + 1);
203 }
204
computeGridCellWeights(float cellWidth,float cellHeight,int x,int y)205 inline tcu::Vec2 computeGridCellWeights(float cellWidth, float cellHeight, int x, int y)
206 {
207 float gx = ((float)x + 0.5f) / cellWidth;
208 float gy = ((float)y + 0.5f) / cellHeight;
209 return tcu::Vec2(deFloatFrac(gx), deFloatFrac(gy));
210 }
211
toColor(tcu::Vec4 rgba)212 inline tcu::RGBA toColor(tcu::Vec4 rgba)
213 {
214 return tcu::RGBA(
215 deClamp32(deRoundFloatToInt32(rgba.x() * 255), 0, 255), deClamp32(deRoundFloatToInt32(rgba.y() * 255), 0, 255),
216 deClamp32(deRoundFloatToInt32(rgba.z() * 255), 0, 255), deClamp32(deRoundFloatToInt32(rgba.w() * 255), 0, 255));
217 }
218
execute(const Shader & vertexShader,const Shader & fragmentShader,const vector<VariableValue> & uniformValues)219 void ProgramExecutor::execute(const Shader &vertexShader, const Shader &fragmentShader,
220 const vector<VariableValue> &uniformValues)
221 {
222 int gridVtxWidth = m_gridWidth + 1;
223 int gridVtxHeight = m_gridHeight + 1;
224 int numVertices = gridVtxWidth * gridVtxHeight;
225
226 VaryingStore varyingStore(numVertices);
227
228 // Execute vertex shader
229 {
230 ExecutionContext execCtx(m_samplers2D, m_samplersCube);
231 int numPackets = numVertices + ((numVertices % EXEC_VEC_WIDTH) ? 1 : 0);
232
233 const vector<ShaderInput *> &inputs = vertexShader.getInputs();
234 vector<const Variable *> outputs;
235 vertexShader.getOutputs(outputs);
236
237 // Set uniform values
238 for (vector<VariableValue>::const_iterator uniformIter = uniformValues.begin();
239 uniformIter != uniformValues.end(); uniformIter++)
240 execCtx.getValue(uniformIter->getVariable()) = uniformIter->getValue().value();
241
242 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
243 {
244 int packetStart = packetNdx * EXEC_VEC_WIDTH;
245 int packetEnd = deMin32((packetNdx + 1) * EXEC_VEC_WIDTH, numVertices);
246
247 // Compute values for vertex shader inputs
248 for (vector<ShaderInput *>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
249 {
250 const ShaderInput *input = *i;
251 ExecValueAccess access = execCtx.getValue(input->getVariable());
252
253 for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
254 {
255 int y = (vtxNdx / gridVtxWidth);
256 int x = vtxNdx - y * gridVtxWidth;
257 float xf = (float)x / (float)(gridVtxWidth - 1);
258 float yf = (float)y / (float)(gridVtxHeight - 1);
259
260 interpolateVertexInput(access, vtxNdx - packetStart, input->getValueRange(), xf, yf);
261 }
262 }
263
264 // Execute vertex shader for packet
265 vertexShader.execute(execCtx);
266
267 // Store output values
268 for (vector<const Variable *>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
269 {
270 const Variable *output = *i;
271
272 if (deStringEqual(output->getName(), "gl_Position"))
273 continue; // Do not store position
274
275 ExecConstValueAccess access = execCtx.getValue(output);
276 VaryingStorage *dst = varyingStore.getStorage(output->getType(), output->getName());
277
278 for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
279 {
280 ValueAccess varyingAccess = dst->getValue(output->getType(), vtxNdx);
281 copyVarying(varyingAccess, access, vtxNdx - packetStart);
282 }
283 }
284 }
285 }
286
287 // Execute fragment shader
288 {
289 ExecutionContext execCtx(m_samplers2D, m_samplersCube);
290
291 // Assign uniform values
292 for (vector<VariableValue>::const_iterator i = uniformValues.begin(); i != uniformValues.end(); i++)
293 execCtx.getValue(i->getVariable()) = i->getValue().value();
294
295 const vector<ShaderInput *> &inputs = fragmentShader.getInputs();
296 const Variable *fragColorVar = DE_NULL;
297 vector<const Variable *> outputs;
298
299 // Find fragment shader output assigned to location 0. This is fragment color.
300 fragmentShader.getOutputs(outputs);
301 for (vector<const Variable *>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
302 {
303 if ((*i)->getLayoutLocation() == 0)
304 {
305 fragColorVar = *i;
306 break;
307 }
308 }
309 TCU_CHECK(fragColorVar);
310
311 int width = m_dst.getWidth();
312 int height = m_dst.getHeight();
313 int numPackets = (width * height) / EXEC_VEC_WIDTH + (((width * height) % EXEC_VEC_WIDTH) ? 1 : 0);
314
315 float cellWidth = (float)width / (float)m_gridWidth;
316 float cellHeight = (float)height / (float)m_gridHeight;
317
318 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
319 {
320 int packetStart = packetNdx * EXEC_VEC_WIDTH;
321 int packetEnd = deMin32((packetNdx + 1) * EXEC_VEC_WIDTH, width * height);
322
323 // Interpolate varyings
324 for (vector<ShaderInput *>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
325 {
326 const ShaderInput *input = *i;
327 ExecValueAccess access = execCtx.getValue(input->getVariable());
328 const VariableType &type = input->getVariable()->getType();
329 const VaryingStorage *src = varyingStore.getStorage(type, input->getVariable()->getName());
330
331 // \todo [2011-03-08 pyry] Part of this could be pre-computed...
332 for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
333 {
334 int y = fragNdx / width;
335 int x = fragNdx - y * width;
336 tcu::IVec4 vtxIndices =
337 computeVertexIndices(cellWidth, cellHeight, gridVtxWidth, gridVtxHeight, x, y);
338 tcu::Vec2 weights = computeGridCellWeights(cellWidth, cellHeight, x, y);
339
340 interpolateFragmentInput(access, fragNdx - packetStart, src->getValue(type, vtxIndices.x()),
341 src->getValue(type, vtxIndices.y()), src->getValue(type, vtxIndices.z()),
342 src->getValue(type, vtxIndices.w()), weights.x(), weights.y());
343 }
344 }
345
346 // Execute fragment shader
347 fragmentShader.execute(execCtx);
348
349 // Write resulting color
350 ExecConstValueAccess colorValue = execCtx.getValue(fragColorVar);
351 for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
352 {
353 int y = fragNdx / width;
354 int x = fragNdx - y * width;
355 int cNdx = fragNdx - packetStart;
356 tcu::Vec4 c = tcu::Vec4(colorValue.component(0).asFloat(cNdx), colorValue.component(1).asFloat(cNdx),
357 colorValue.component(2).asFloat(cNdx), colorValue.component(3).asFloat(cNdx));
358
359 // \todo [2012-11-13 pyry] Reverse order.
360 m_dst.setPixel(c, x, m_dst.getHeight() - y - 1);
361 }
362 }
363 }
364 }
365
366 } // namespace rsg
367