| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Random Shader Generator |
| * ---------------------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Program Executor. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "rsgProgramExecutor.hpp" |
| #include "rsgExecutionContext.hpp" |
| #include "rsgVariableValue.hpp" |
| #include "rsgUtils.hpp" |
| #include "tcuSurface.hpp" |
| #include "deMath.h" |
| #include "deString.h" |
| |
| #include <set> |
| #include <string> |
| #include <map> |
| |
| using std::set; |
| using std::string; |
| using std::vector; |
| using std::map; |
| |
| namespace rsg |
| { |
| |
| class VaryingStorage |
| { |
| public: |
| VaryingStorage (const VariableType& type, int numVertices); |
| ~VaryingStorage (void) {} |
| |
| ValueAccess getValue (const VariableType& type, int vtxNdx); |
| ConstValueAccess getValue (const VariableType& type, int vtxNdx) const; |
| |
| private: |
| std::vector<Scalar> m_value; |
| }; |
| |
| VaryingStorage::VaryingStorage (const VariableType& type, int numVertices) |
| : m_value(type.getScalarSize()*numVertices) |
| { |
| } |
| |
| ValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx) |
| { |
| return ValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]); |
| } |
| |
| ConstValueAccess VaryingStorage::getValue (const VariableType& type, int vtxNdx) const |
| { |
| return ConstValueAccess(type, &m_value[type.getScalarSize()*vtxNdx]); |
| } |
| |
| class VaryingStore |
| { |
| public: |
| VaryingStore (int numVertices); |
| ~VaryingStore (void); |
| |
| VaryingStorage* getStorage (const VariableType& type, const char* name); |
| |
| private: |
| int m_numVertices; |
| std::map<std::string, VaryingStorage*> m_values; |
| }; |
| |
| VaryingStore::VaryingStore (int numVertices) |
| : m_numVertices(numVertices) |
| { |
| } |
| |
| VaryingStore::~VaryingStore (void) |
| { |
| for (map<string, VaryingStorage*>::iterator i = m_values.begin(); i != m_values.end(); i++) |
| delete i->second; |
| m_values.clear(); |
| } |
| |
| VaryingStorage* VaryingStore::getStorage (const VariableType& type, const char* name) |
| { |
| VaryingStorage* storage = m_values[name]; |
| |
| if (!storage) |
| { |
| storage = new VaryingStorage(type, m_numVertices); |
| m_values[name] = storage; |
| } |
| |
| return storage; |
| } |
| |
| inline float interpolateVertexQuad (const tcu::Vec4& quad, float x, float y) |
| { |
| float w00 = (1.0f-x)*(1.0f-y); |
| float w01 = (1.0f-x)*y; |
| float w10 = x*(1.0f-y); |
| float w11 = x*y; |
| return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11; |
| } |
| |
| inline float interpolateVertex (float x0y0, float x1y1, float x, float y) |
| { |
| return interpolateVertexQuad(tcu::Vec4(x0y0, (x0y0+x1y1)*0.5f, (x0y0+x1y1)*0.5f, x1y1), x, y); |
| } |
| |
| inline float interpolateTri (float v0, float v1, float v2, float x, float y) |
| { |
| return v0 + (v1-v0)*x + (v2-v0)*y; |
| } |
| |
| inline float interpolateFragment (const tcu::Vec4& quad, float x, float y) |
| { |
| if (x + y < 1.0f) |
| return interpolateTri(quad.x(), quad.y(), quad.z(), x, y); |
| else |
| return interpolateTri(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y); |
| } |
| |
| template <int Stride> |
| void interpolateVertexInput (StridedValueAccess<Stride> dst, int dstComp, const ConstValueRangeAccess valueRange, float x, float y) |
| { |
| TCU_CHECK(valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT); |
| int numElements = valueRange.getType().getNumElements(); |
| for (int elementNdx = 0; elementNdx < numElements; elementNdx++) |
| { |
| float xd, yd; |
| getVertexInterpolationCoords(xd, yd, x, y, elementNdx); |
| dst.component(elementNdx).asFloat(dstComp) = interpolateVertex(valueRange.getMin().component(elementNdx).asFloat(), valueRange.getMax().component(elementNdx).asFloat(), xd, yd); |
| } |
| } |
| |
| template <int Stride> |
| void interpolateFragmentInput (StridedValueAccess<Stride> dst, int dstComp, ConstValueAccess vtx0, ConstValueAccess vtx1, ConstValueAccess vtx2, ConstValueAccess vtx3, float x, float y) |
| { |
| TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT); |
| int numElements = dst.getType().getNumElements(); |
| for (int ndx = 0; ndx < numElements; ndx++) |
| 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); |
| } |
| |
| template <int Stride> |
| void copyVarying (ValueAccess dst, ConstStridedValueAccess<Stride> src, int compNdx) |
| { |
| TCU_CHECK(dst.getType().getBaseType() == VariableType::TYPE_FLOAT); |
| for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) |
| dst.component(elemNdx).asFloat() = src.component(elemNdx).asFloat(compNdx); |
| } |
| |
| ProgramExecutor::ProgramExecutor (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight) |
| : m_dst (dst) |
| , m_gridWidth (gridWidth) |
| , m_gridHeight (gridHeight) |
| { |
| } |
| |
| ProgramExecutor::~ProgramExecutor (void) |
| { |
| } |
| |
| void ProgramExecutor::setTexture (int samplerNdx, const tcu::Texture2D* texture, const tcu::Sampler& sampler) |
| { |
| m_samplers2D[samplerNdx] = Sampler2D(texture, sampler); |
| } |
| |
| void ProgramExecutor::setTexture (int samplerNdx, const tcu::TextureCube* texture, const tcu::Sampler& sampler) |
| { |
| m_samplersCube[samplerNdx] = SamplerCube(texture, sampler); |
| } |
| |
| inline tcu::IVec4 computeVertexIndices (float cellWidth, float cellHeight, int gridVtxWidth, int gridVtxHeight, int x, int y) |
| { |
| DE_UNREF(gridVtxHeight); |
| int x0 = (int)deFloatFloor((float)x / cellWidth); |
| int y0 = (int)deFloatFloor((float)y / cellHeight); |
| return tcu::IVec4(y0*gridVtxWidth + x0, y0*gridVtxWidth + x0 + 1, (y0+1)*gridVtxWidth + x0, (y0+1)*gridVtxWidth + x0 + 1); |
| } |
| |
| inline tcu::Vec2 computeGridCellWeights (float cellWidth, float cellHeight, int x, int y) |
| { |
| float gx = ((float)x + 0.5f) / cellWidth; |
| float gy = ((float)y + 0.5f) / cellHeight; |
| return tcu::Vec2(deFloatFrac(gx), deFloatFrac(gy)); |
| } |
| |
| inline tcu::RGBA toColor (tcu::Vec4 rgba) |
| { |
| return tcu::RGBA(deClamp32(deRoundFloatToInt32(rgba.x()*255), 0, 255), |
| deClamp32(deRoundFloatToInt32(rgba.y()*255), 0, 255), |
| deClamp32(deRoundFloatToInt32(rgba.z()*255), 0, 255), |
| deClamp32(deRoundFloatToInt32(rgba.w()*255), 0, 255)); |
| } |
| |
| void ProgramExecutor::execute (const Shader& vertexShader, const Shader& fragmentShader, const vector<VariableValue>& uniformValues) |
| { |
| int gridVtxWidth = m_gridWidth+1; |
| int gridVtxHeight = m_gridHeight+1; |
| int numVertices = gridVtxWidth*gridVtxHeight; |
| |
| VaryingStore varyingStore(numVertices); |
| |
| // Execute vertex shader |
| { |
| ExecutionContext execCtx(m_samplers2D, m_samplersCube); |
| int numPackets = numVertices + ((numVertices%EXEC_VEC_WIDTH) ? 1 : 0); |
| |
| const vector<ShaderInput*>& inputs = vertexShader.getInputs(); |
| vector<const Variable*> outputs; |
| vertexShader.getOutputs(outputs); |
| |
| // Set uniform values |
| for (vector<VariableValue>::const_iterator uniformIter = uniformValues.begin(); uniformIter != uniformValues.end(); uniformIter++) |
| execCtx.getValue(uniformIter->getVariable()) = uniformIter->getValue().value(); |
| |
| for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) |
| { |
| int packetStart = packetNdx*EXEC_VEC_WIDTH; |
| int packetEnd = deMin32((packetNdx+1)*EXEC_VEC_WIDTH, numVertices); |
| |
| // Compute values for vertex shader inputs |
| for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++) |
| { |
| const ShaderInput* input = *i; |
| ExecValueAccess access = execCtx.getValue(input->getVariable()); |
| |
| for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++) |
| { |
| int y = (vtxNdx/gridVtxWidth); |
| int x = vtxNdx - y*gridVtxWidth; |
| float xf = (float)x / (float)(gridVtxWidth-1); |
| float yf = (float)y / (float)(gridVtxHeight-1); |
| |
| interpolateVertexInput(access, vtxNdx-packetStart, input->getValueRange(), xf, yf); |
| } |
| } |
| |
| // Execute vertex shader for packet |
| vertexShader.execute(execCtx); |
| |
| // Store output values |
| for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++) |
| { |
| const Variable* output = *i; |
| |
| if (deStringEqual(output->getName(), "gl_Position")) |
| continue; // Do not store position |
| |
| ExecConstValueAccess access = execCtx.getValue(output); |
| VaryingStorage* dst = varyingStore.getStorage(output->getType(), output->getName()); |
| |
| for (int vtxNdx = packetStart; vtxNdx < packetEnd; vtxNdx++) |
| { |
| ValueAccess varyingAccess = dst->getValue(output->getType(), vtxNdx); |
| copyVarying(varyingAccess, access, vtxNdx-packetStart); |
| } |
| } |
| } |
| } |
| |
| // Execute fragment shader |
| { |
| ExecutionContext execCtx(m_samplers2D, m_samplersCube); |
| |
| // Assign uniform values |
| for (vector<VariableValue>::const_iterator i = uniformValues.begin(); i != uniformValues.end(); i++) |
| execCtx.getValue(i->getVariable()) = i->getValue().value(); |
| |
| const vector<ShaderInput*>& inputs = fragmentShader.getInputs(); |
| const Variable* fragColorVar = DE_NULL; |
| vector<const Variable*> outputs; |
| |
| // Find fragment shader output assigned to location 0. This is fragment color. |
| fragmentShader.getOutputs(outputs); |
| for (vector<const Variable*>::const_iterator i = outputs.begin(); i != outputs.end(); i++) |
| { |
| if ((*i)->getLayoutLocation() == 0) |
| { |
| fragColorVar = *i; |
| break; |
| } |
| } |
| TCU_CHECK(fragColorVar); |
| |
| int width = m_dst.getWidth(); |
| int height = m_dst.getHeight(); |
| int numPackets = (width*height)/EXEC_VEC_WIDTH + (((width*height)%EXEC_VEC_WIDTH) ? 1 : 0); |
| |
| float cellWidth = (float)width / (float)m_gridWidth; |
| float cellHeight = (float)height / (float)m_gridHeight; |
| |
| for (int packetNdx = 0; packetNdx < numPackets; packetNdx++) |
| { |
| int packetStart = packetNdx*EXEC_VEC_WIDTH; |
| int packetEnd = deMin32((packetNdx+1)*EXEC_VEC_WIDTH, width*height); |
| |
| // Interpolate varyings |
| for (vector<ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++) |
| { |
| const ShaderInput* input = *i; |
| ExecValueAccess access = execCtx.getValue(input->getVariable()); |
| const VariableType& type = input->getVariable()->getType(); |
| const VaryingStorage* src = varyingStore.getStorage(type, input->getVariable()->getName()); |
| |
| // \todo [2011-03-08 pyry] Part of this could be pre-computed... |
| for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++) |
| { |
| int y = fragNdx/width; |
| int x = fragNdx - y*width; |
| tcu::IVec4 vtxIndices = computeVertexIndices(cellWidth, cellHeight, gridVtxWidth, gridVtxHeight, x, y); |
| tcu::Vec2 weights = computeGridCellWeights(cellWidth, cellHeight, x, y); |
| |
| interpolateFragmentInput(access, fragNdx-packetStart, |
| src->getValue(type, vtxIndices.x()), |
| src->getValue(type, vtxIndices.y()), |
| src->getValue(type, vtxIndices.z()), |
| src->getValue(type, vtxIndices.w()), |
| weights.x(), weights.y()); |
| } |
| } |
| |
| // Execute fragment shader |
| fragmentShader.execute(execCtx); |
| |
| // Write resulting color |
| ExecConstValueAccess colorValue = execCtx.getValue(fragColorVar); |
| for (int fragNdx = packetStart; fragNdx < packetEnd; fragNdx++) |
| { |
| int y = fragNdx/width; |
| int x = fragNdx - y*width; |
| int cNdx = fragNdx-packetStart; |
| tcu::Vec4 c = tcu::Vec4(colorValue.component(0).asFloat(cNdx), |
| colorValue.component(1).asFloat(cNdx), |
| colorValue.component(2).asFloat(cNdx), |
| colorValue.component(3).asFloat(cNdx)); |
| |
| // \todo [2012-11-13 pyry] Reverse order. |
| m_dst.setPixel(c, x, m_dst.getHeight()-y-1); |
| } |
| } |
| } |
| } |
| |
| } // rsg |