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 361