1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Random Shader Generator
3 * ----------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Program Executor.
22 *//*--------------------------------------------------------------------*/
24 #include "rsgProgramExecutor.hpp"
25 #include "rsgExecutionContext.hpp"
26 #include "rsgVariableValue.hpp"
27 #include "rsgUtils.hpp"
28 #include "tcuSurface.hpp"
47 VaryingStorage (const VariableType& type, int numVertices);
48 ~VaryingStorage (void) {}
50 ValueAccess getValue (const VariableType& type, int vtxNdx);
51 ConstValueAccess getValue (const VariableType& type, int vtxNdx) const;
54 std::vector<Scalar> m_value;
57 VaryingStorage::VaryingStorage (const VariableType& type, int numVertices)
58 : m_value(type.getScalarSize()*numVertices)
62 ValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx)
64 return ValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
67 ConstValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx) const
69 return ConstValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
75 VaryingStore (int numVertices);
78 VaryingStorage* getStorage (const VariableType& type, const char* name);
82 std::map<std::string, VaryingStorage*> m_values;
85 VaryingStore::VaryingStore (int numVertices)
86 : m_numVertices(numVertices)
90 VaryingStore::~VaryingStore (void)
92 for (map<string, VaryingStorage*>::iterator i = m_values.begin(); i != m_values.end(); i++)
97 VaryingStorage* VaryingStore::getStorage (const VariableType& type, const char* name)
99 VaryingStorage* storage = m_values[name];
103 storage = new VaryingStorage(type, m_numVertices);
104 m_values[name] = storage;
110 inline float interpolateVertexQuad (const tcu::Vec4& quad, float x, float y)
112 float w00 = (1.0f-x)*(1.0f-y);
113 float w01 = (1.0f-x)*y;
114 float w10 = x*(1.0f-y);
116 return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
119 inline float interpolateVertex (float x0y0, float x1y1, float x, float y)
121 return interpolateVertexQuad(tcu::Vec4(x0y0, (x0y0+x1y1)*0.5f, (x0y0+x1y1)*0.5f, x1y1), x, y);
124 inline float interpolateTri (float v0, float v1, float v2, float x, float y)
126 return v0 + (v1-v0)*x + (v2-v0)*y;
129 inline float interpolateFragment (const tcu::Vec4& quad, float x, float y)
132 return interpolateTri(quad.x(), quad.y(), quad.z(), x, y);
134 return interpolateTri(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
137 template <int Stride>
138 void interpolateVertexInput (StridedValueAccess<Stride> dst, int dstComp, const ConstValueRangeAccess valueRange, float x, float y)
140 TCU_CHECK(valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT);
141 int numElements = valueRange.getType().getNumElements();
142 for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
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);
150 template <int Stride>
151 void interpolateFragmentInput (StridedValueAccess<Stride> dst, int dstComp, ConstValueAccess vtx0, ConstValueAccess vtx1, ConstValueAccess vtx2, ConstValueAccess vtx3, float x, float y)
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);
159 template <int Stride>
160 void copyVarying (ValueAccess dst, ConstStridedValueAccess<Stride> src, int compNdx)
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);
167 ProgramExecutor::ProgramExecutor (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight)
169 , m_gridWidth (gridWidth)
170 , m_gridHeight (gridHeight)
174 ProgramExecutor::~ProgramExecutor (void)
178 void ProgramExecutor::setTexture (int samplerNdx, const tcu::Texture2D* texture, const tcu::Sampler& sampler)
180 m_samplers2D[samplerNdx] = Sampler2D(texture, sampler);
183 void ProgramExecutor::setTexture (int samplerNdx, const tcu::TextureCube* texture, const tcu::Sampler& sampler)
185 m_samplersCube[samplerNdx] = SamplerCube(texture, sampler);
188 inline tcu::IVec4 computeVertexIndices (float cellWidth, float cellHeight, int gridVtxWidth, int gridVtxHeight, int x, int y)
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);
196 inline tcu::Vec2 computeGridCellWeights (float cellWidth, float cellHeight, int x, int y)
198 float gx = ((float)x + 0.5f) / cellWidth;
199 float gy = ((float)y + 0.5f) / cellHeight;
200 return tcu::Vec2(deFloatFrac(gx), deFloatFrac(gy));
203 inline tcu::RGBA toColor (tcu::Vec4 rgba)
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));
211 void ProgramExecutor::execute (const Shader& vertexShader, const Shader& fragmentShader, const vector<VariableValue>& uniformValues)
213 int gridVtxWidth = m_gridWidth+1;
214 int gridVtxHeight = m_gridHeight+1;
215 int numVertices = gridVtxWidth*gridVtxHeight;
217 VaryingStore varyingStore(numVertices);
219 // Execute vertex shader
221 ExecutionContext execCtx(m_samplers2D, m_samplersCube);
222 int numPackets = numVertices + ((numVertices%EXEC_VEC_WIDTH) ? 1 : 0);
224 const vector<ShaderInput*>& inputs = vertexShader.getInputs();
225 vector<const Variable*> outputs;
226 vertexShader.getOutputs(outputs);
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();
232 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
234 int packetStart = packetNdx*EXEC_VEC_WIDTH;
235 int packetEnd = deMin32((packetNdx+1)*EXEC_VEC_WIDTH, numVertices);
237 // Compute values for vertex shader inputs
238 for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
240 const ShaderInput* input = *i;
241 ExecValueAccess access = execCtx.getValue(input->getVariable());
243 for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
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);
250 interpolateVertexInput(access, vtxNdx-packetStart, input->getValueRange(), xf, yf);
254 // Execute vertex shader for packet
255 vertexShader.execute(execCtx);
257 // Store output values
258 for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
260 const Variable* output = *i;
262 if (deStringEqual(output->getName(), "gl_Position"))
263 continue; // Do not store position
265 ExecConstValueAccess access = execCtx.getValue(output);
266 VaryingStorage* dst = varyingStore.getStorage(output->getType(), output->getName());
268 for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++)
270 ValueAccess varyingAccess = dst->getValue(output->getType(), vtxNdx);
271 copyVarying(varyingAccess, access, vtxNdx-packetStart);
277 // Execute fragment shader
279 ExecutionContext execCtx(m_samplers2D, m_samplersCube);
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();
285 const vector<ShaderInput*>& inputs = fragmentShader.getInputs();
286 const Variable* fragColorVar = DE_NULL;
287 vector<const Variable*> outputs;
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++)
293 if ((*i)->getLayoutLocation() == 0)
299 TCU_CHECK(fragColorVar);
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);
305 float cellWidth = (float)width / (float)m_gridWidth;
306 float cellHeight = (float)height / (float)m_gridHeight;
308 for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
310 int packetStart = packetNdx*EXEC_VEC_WIDTH;
311 int packetEnd = deMin32((packetNdx+1)*EXEC_VEC_WIDTH, width*height);
313 // Interpolate varyings
314 for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
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());
321 // \todo [2011-03-08 pyry] Part of this could be pre-computed...
322 for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
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);
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());
338 // Execute fragment shader
339 fragmentShader.execute(execCtx);
341 // Write resulting color
342 ExecConstValueAccess colorValue = execCtx.getValue(fragColorVar);
343 for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++)
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));
353 // \todo [2012-11-13 pyry] Reverse order.
354 m_dst.setPixel(c, x, m_dst.getHeight()-y-1);