| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL (ES) Module |
| * ----------------------------------------------- |
| * |
| * 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 sglr-rsg adaptation. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "glsRandomShaderProgram.hpp" |
| #include "rsgShader.hpp" |
| |
| namespace deqp |
| { |
| namespace gls |
| { |
| |
| using std::vector; |
| |
| static rr::GenericVecType mapToGenericVecType(const rsg::VariableType &varType) |
| { |
| if (varType.isFloatOrVec()) |
| return rr::GENERICVECTYPE_FLOAT; |
| else if (varType.isIntOrVec()) |
| return rr::GENERICVECTYPE_INT32; |
| else |
| { |
| DE_ASSERT(false); |
| return rr::GENERICVECTYPE_LAST; |
| } |
| } |
| |
| static glu::DataType mapToBasicType(const rsg::VariableType &varType) |
| { |
| if (varType.isFloatOrVec() || varType.isIntOrVec() || varType.isBoolOrVec()) |
| { |
| const glu::DataType scalarType = varType.isFloatOrVec() ? glu::TYPE_FLOAT : |
| varType.isIntOrVec() ? glu::TYPE_INT : |
| varType.isBoolOrVec() ? glu::TYPE_BOOL : |
| glu::TYPE_LAST; |
| const int numComps = varType.getNumElements(); |
| |
| DE_ASSERT(de::inRange(numComps, 1, 4)); |
| return glu::DataType(scalarType + numComps - 1); |
| } |
| else if (varType.getBaseType() == rsg::VariableType::TYPE_SAMPLER_2D) |
| return glu::TYPE_SAMPLER_2D; |
| else if (varType.getBaseType() == rsg::VariableType::TYPE_SAMPLER_CUBE) |
| return glu::TYPE_SAMPLER_CUBE; |
| else |
| { |
| DE_ASSERT(false); |
| return glu::TYPE_LAST; |
| } |
| } |
| |
| static void generateProgramDeclaration(sglr::pdec::ShaderProgramDeclaration &decl, const rsg::Shader &vertexShader, |
| const rsg::Shader &fragmentShader, int numUnifiedUniforms, |
| const rsg::ShaderInput *const *unifiedUniforms) |
| { |
| decl << sglr::pdec::VertexSource(vertexShader.getSource()) |
| << sglr::pdec::FragmentSource(fragmentShader.getSource()); |
| |
| for (vector<rsg::ShaderInput *>::const_iterator vtxInIter = vertexShader.getInputs().begin(); |
| vtxInIter != vertexShader.getInputs().end(); ++vtxInIter) |
| { |
| const rsg::ShaderInput *vertexInput = *vtxInIter; |
| decl << sglr::pdec::VertexAttribute(vertexInput->getVariable()->getName(), |
| mapToGenericVecType(vertexInput->getVariable()->getType())); |
| } |
| |
| for (vector<rsg::ShaderInput *>::const_iterator fragInIter = fragmentShader.getInputs().begin(); |
| fragInIter != fragmentShader.getInputs().end(); ++fragInIter) |
| { |
| const rsg::ShaderInput *fragInput = *fragInIter; |
| decl << sglr::pdec::VertexToFragmentVarying(mapToGenericVecType(fragInput->getVariable()->getType())); |
| } |
| |
| for (int uniformNdx = 0; uniformNdx < numUnifiedUniforms; uniformNdx++) |
| { |
| const rsg::ShaderInput *uniform = unifiedUniforms[uniformNdx]; |
| decl << sglr::pdec::Uniform(uniform->getVariable()->getName(), |
| mapToBasicType(uniform->getVariable()->getType())); |
| } |
| |
| decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT); |
| } |
| |
| static sglr::pdec::ShaderProgramDeclaration generateProgramDeclaration(const rsg::Shader &vertexShader, |
| const rsg::Shader &fragmentShader, |
| int numUnifiedUniforms, |
| const rsg::ShaderInput *const *unifiedUniforms) |
| { |
| sglr::pdec::ShaderProgramDeclaration decl; |
| generateProgramDeclaration(decl, vertexShader, fragmentShader, numUnifiedUniforms, unifiedUniforms); |
| return decl; |
| } |
| |
| static const rsg::Variable *findShaderOutputByName(const rsg::Shader &shader, const char *name) |
| { |
| vector<const rsg::Variable *> outputs; |
| shader.getOutputs(outputs); |
| |
| for (vector<const rsg::Variable *>::const_iterator iter = outputs.begin(); iter != outputs.end(); ++iter) |
| { |
| if (deStringEqual((*iter)->getName(), name)) |
| return *iter; |
| } |
| |
| return DE_NULL; |
| } |
| |
| static const rsg::Variable *findShaderOutputByLocation(const rsg::Shader &shader, int location) |
| { |
| vector<const rsg::Variable *> outputs; |
| shader.getOutputs(outputs); |
| |
| for (vector<const rsg::Variable *>::const_iterator iter = outputs.begin(); iter != outputs.end(); iter++) |
| { |
| if ((*iter)->getLayoutLocation() == location) |
| return *iter; |
| } |
| |
| return DE_NULL; |
| } |
| |
| RandomShaderProgram::RandomShaderProgram(const rsg::Shader &vertexShader, const rsg::Shader &fragmentShader, |
| int numUnifiedUniforms, const rsg::ShaderInput *const *unifiedUniforms) |
| : sglr::ShaderProgram(generateProgramDeclaration(vertexShader, fragmentShader, numUnifiedUniforms, unifiedUniforms)) |
| , m_vertexShader(vertexShader) |
| , m_fragmentShader(fragmentShader) |
| , m_numUnifiedUniforms(numUnifiedUniforms) |
| , m_unifiedUniforms(unifiedUniforms) |
| , m_positionVar(findShaderOutputByName(vertexShader, "gl_Position")) |
| , m_fragColorVar(findShaderOutputByLocation(fragmentShader, 0)) |
| , m_execCtx(m_sampler2DMap, m_samplerCubeMap) |
| { |
| TCU_CHECK_INTERNAL(m_positionVar && m_positionVar->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT && |
| m_positionVar->getType().getNumElements() == 4); |
| TCU_CHECK_INTERNAL(m_fragColorVar && m_fragColorVar->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT && |
| m_fragColorVar->getType().getNumElements() == 4); |
| |
| // Build list of vertex outputs. |
| for (vector<rsg::ShaderInput *>::const_iterator fragInIter = fragmentShader.getInputs().begin(); |
| fragInIter != fragmentShader.getInputs().end(); ++fragInIter) |
| { |
| const rsg::ShaderInput *fragInput = *fragInIter; |
| const rsg::Variable *vertexOutput = findShaderOutputByName(vertexShader, fragInput->getVariable()->getName()); |
| |
| TCU_CHECK_INTERNAL(vertexOutput); |
| m_vertexOutputs.push_back(vertexOutput); |
| } |
| } |
| |
| void RandomShaderProgram::refreshUniforms(void) const |
| { |
| DE_ASSERT(m_numUnifiedUniforms == (int)m_uniforms.size()); |
| |
| for (int uniformNdx = 0; uniformNdx < m_numUnifiedUniforms; uniformNdx++) |
| { |
| const rsg::Variable *uniformVar = m_unifiedUniforms[uniformNdx]->getVariable(); |
| const rsg::VariableType &uniformType = uniformVar->getType(); |
| const sglr::UniformSlot &uniformSlot = m_uniforms[uniformNdx]; |
| |
| m_execCtx.getValue(uniformVar) = |
| rsg::ConstValueAccess(uniformType, (const rsg::Scalar *)&uniformSlot.value).value(); |
| } |
| } |
| |
| void RandomShaderProgram::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, |
| const int numPackets) const |
| { |
| // \todo [2013-12-13 pyry] Do only when necessary. |
| refreshUniforms(); |
| |
| int packetOffset = 0; |
| |
| while (packetOffset < numPackets) |
| { |
| const int numToExecute = de::min(numPackets - packetOffset, (int)rsg::EXEC_VEC_WIDTH); |
| |
| // Fetch attributes. |
| for (int attribNdx = 0; attribNdx < (int)m_vertexShader.getInputs().size(); ++attribNdx) |
| { |
| const rsg::Variable *attribVar = m_vertexShader.getInputs()[attribNdx]->getVariable(); |
| const rsg::VariableType &attribType = attribVar->getType(); |
| const int numComponents = attribType.getNumElements(); |
| rsg::ExecValueAccess access = m_execCtx.getValue(attribVar); |
| |
| DE_ASSERT(attribType.isFloatOrVec() && de::inRange(numComponents, 1, 4)); |
| |
| for (int ndx = 0; ndx < numToExecute; ndx++) |
| { |
| const int packetNdx = ndx + packetOffset; |
| const rr::VertexPacket *packet = packets[packetNdx]; |
| const tcu::Vec4 attribValue = |
| rr::readVertexAttribFloat(inputs[attribNdx], packet->instanceNdx, packet->vertexNdx); |
| |
| access.component(0).asFloat(ndx) = attribValue[0]; |
| if (numComponents >= 2) |
| access.component(1).asFloat(ndx) = attribValue[1]; |
| if (numComponents >= 3) |
| access.component(2).asFloat(ndx) = attribValue[2]; |
| if (numComponents >= 4) |
| access.component(3).asFloat(ndx) = attribValue[3]; |
| } |
| } |
| |
| m_vertexShader.execute(m_execCtx); |
| |
| // Store position |
| { |
| const rsg::ExecConstValueAccess access = m_execCtx.getValue(m_positionVar); |
| |
| for (int ndx = 0; ndx < numToExecute; ndx++) |
| { |
| const int packetNdx = ndx + packetOffset; |
| rr::VertexPacket *packet = packets[packetNdx]; |
| |
| packet->position[0] = access.component(0).asFloat(ndx); |
| packet->position[1] = access.component(1).asFloat(ndx); |
| packet->position[2] = access.component(2).asFloat(ndx); |
| packet->position[3] = access.component(3).asFloat(ndx); |
| } |
| } |
| |
| // Other varyings |
| for (int varNdx = 0; varNdx < (int)m_vertexOutputs.size(); varNdx++) |
| { |
| const rsg::Variable *var = m_vertexOutputs[varNdx]; |
| const rsg::VariableType &varType = var->getType(); |
| const int numComponents = varType.getNumElements(); |
| const rsg::ExecConstValueAccess access = m_execCtx.getValue(var); |
| |
| DE_ASSERT(varType.isFloatOrVec() && de::inRange(numComponents, 1, 4)); |
| |
| for (int ndx = 0; ndx < numToExecute; ndx++) |
| { |
| const int packetNdx = ndx + packetOffset; |
| rr::VertexPacket *const packet = packets[packetNdx]; |
| float *const dst = packet->outputs[varNdx].getAccess<float>(); |
| |
| dst[0] = access.component(0).asFloat(ndx); |
| if (numComponents >= 2) |
| dst[1] = access.component(1).asFloat(ndx); |
| if (numComponents >= 3) |
| dst[2] = access.component(2).asFloat(ndx); |
| if (numComponents >= 4) |
| dst[3] = access.component(3).asFloat(ndx); |
| } |
| } |
| |
| packetOffset += numToExecute; |
| } |
| } |
| |
| void RandomShaderProgram::shadeFragments(rr::FragmentPacket *packets, const int numPackets, |
| const rr::FragmentShadingContext &context) const |
| { |
| const rsg::ExecConstValueAccess fragColorAccess = m_execCtx.getValue(m_fragColorVar); |
| int packetOffset = 0; |
| |
| DE_STATIC_ASSERT(rsg::EXEC_VEC_WIDTH % rr::NUM_FRAGMENTS_PER_PACKET == 0); |
| |
| while (packetOffset < numPackets) |
| { |
| const int numPacketsToExecute = |
| de::min(numPackets - packetOffset, (int)rsg::EXEC_VEC_WIDTH / (int)rr::NUM_FRAGMENTS_PER_PACKET); |
| |
| // Interpolate varyings. |
| for (int varNdx = 0; varNdx < (int)m_fragmentShader.getInputs().size(); ++varNdx) |
| { |
| const rsg::Variable *var = m_fragmentShader.getInputs()[varNdx]->getVariable(); |
| const rsg::VariableType &varType = var->getType(); |
| const int numComponents = varType.getNumElements(); |
| rsg::ExecValueAccess access = m_execCtx.getValue(var); |
| |
| DE_ASSERT(varType.isFloatOrVec() && de::inRange(numComponents, 1, 4)); |
| |
| for (int packetNdx = 0; packetNdx < numPacketsToExecute; packetNdx++) |
| { |
| const rr::FragmentPacket &packet = packets[packetOffset + packetNdx]; |
| |
| for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; fragNdx++) |
| { |
| const tcu::Vec4 varValue = rr::readVarying<float>(packet, context, varNdx, fragNdx); |
| const int dstNdx = packetNdx * rr::NUM_FRAGMENTS_PER_PACKET + fragNdx; |
| |
| access.component(0).asFloat(dstNdx) = varValue[0]; |
| if (numComponents >= 2) |
| access.component(1).asFloat(dstNdx) = varValue[1]; |
| if (numComponents >= 3) |
| access.component(2).asFloat(dstNdx) = varValue[2]; |
| if (numComponents >= 4) |
| access.component(3).asFloat(dstNdx) = varValue[3]; |
| } |
| } |
| } |
| |
| m_fragmentShader.execute(m_execCtx); |
| |
| // Store color |
| for (int packetNdx = 0; packetNdx < numPacketsToExecute; packetNdx++) |
| { |
| for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; fragNdx++) |
| { |
| const int srcNdx = packetNdx * rr::NUM_FRAGMENTS_PER_PACKET + fragNdx; |
| const tcu::Vec4 color( |
| fragColorAccess.component(0).asFloat(srcNdx), fragColorAccess.component(1).asFloat(srcNdx), |
| fragColorAccess.component(2).asFloat(srcNdx), fragColorAccess.component(3).asFloat(srcNdx)); |
| |
| rr::writeFragmentOutput(context, packetOffset + packetNdx, fragNdx, 0, color); |
| } |
| } |
| |
| packetOffset += numPacketsToExecute; |
| } |
| } |
| |
| } // namespace gls |
| } // namespace deqp |