Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame] | 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 | { |
Jarkko Pöyry | ba84b6d | 2015-05-19 17:44:29 -0700 | [diff] [blame] | 198 | float gx = ((float)x + 0.5f) / cellWidth; |
| 199 | float gy = ((float)y + 0.5f) / cellHeight; |
Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame] | 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 |