xref: /aosp_15_r20/external/deqp/framework/randomshaders/rsgProgramExecutor.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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