Merge "Fix extension support checks in negative api tests" into nougat-cts-dev am...
[platform/upstream/VK-GL-CTS.git] / framework / randomshaders / rsgProgramExecutor.cpp
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);
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
57 VaryingStorage::VaryingStorage (const VariableType& type, int numVertices)
58         : m_value(type.getScalarSize()*numVertices)
59 {
60 }
61
62 ValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx)
63 {
64         return ValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]);
65 }
66
67 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
85 VaryingStore::VaryingStore (int numVertices)
86         : m_numVertices(numVertices)
87 {
88 }
89
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
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
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
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
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
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>
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>
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>
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
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
174 ProgramExecutor::~ProgramExecutor (void)
175 {
176 }
177
178 void ProgramExecutor::setTexture (int samplerNdx, const tcu::Texture2D* texture, const tcu::Sampler& sampler)
179 {
180         m_samplers2D[samplerNdx] = Sampler2D(texture, sampler);
181 }
182
183 void ProgramExecutor::setTexture (int samplerNdx, const tcu::TextureCube* texture, const tcu::Sampler& sampler)
184 {
185         m_samplersCube[samplerNdx] = SamplerCube(texture, sampler);
186 }
187
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
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
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
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