/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL Shared 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 Shared shader constant expression test components *//*--------------------------------------------------------------------*/ #include "glsShaderConstExprTests.hpp" #include "glsShaderLibrary.hpp" #include "glsShaderLibraryCase.hpp" #include "tcuStringTemplate.hpp" #include "deStringUtil.hpp" #include "deMath.h" namespace deqp { namespace gls { namespace ShaderConstExpr { static void addOutputVar (glu::sl::ValueBlock* dst, glu::DataType type, float output) { dst->outputs.push_back(glu::sl::Value()); { glu::sl::Value& value = dst->outputs.back(); value.name = "out0"; value.type = glu::VarType(type, glu::PRECISION_LAST); value.elements.resize(1); switch (type) { case glu::TYPE_INT: value.elements[0].int32 = (int)output; break; case glu::TYPE_UINT: value.elements[0].int32 = (unsigned int)output; break; case glu::TYPE_BOOL: value.elements[0].bool32 = output!=0.0f; break; case glu::TYPE_FLOAT: value.elements[0].float32 = output; break; default: DE_ASSERT(false); } } } std::vector createTests (tcu::TestContext& testContext, glu::RenderContext& renderContext, const glu::ContextInfo& contextInfo, const TestParams* cases, int numCases, glu::GLSLVersion version, TestShaderStage testStage) { using std::string; using std::vector; using gls::ShaderLibraryCase; // Needed for autogenerating shader code for increased component counts DE_STATIC_ASSERT(glu::TYPE_FLOAT+1 == glu::TYPE_FLOAT_VEC2); DE_STATIC_ASSERT(glu::TYPE_FLOAT+2 == glu::TYPE_FLOAT_VEC3); DE_STATIC_ASSERT(glu::TYPE_FLOAT+3 == glu::TYPE_FLOAT_VEC4); DE_STATIC_ASSERT(glu::TYPE_INT+1 == glu::TYPE_INT_VEC2); DE_STATIC_ASSERT(glu::TYPE_INT+2 == glu::TYPE_INT_VEC3); DE_STATIC_ASSERT(glu::TYPE_INT+3 == glu::TYPE_INT_VEC4); DE_STATIC_ASSERT(glu::TYPE_UINT+1 == glu::TYPE_UINT_VEC2); DE_STATIC_ASSERT(glu::TYPE_UINT+2 == glu::TYPE_UINT_VEC3); DE_STATIC_ASSERT(glu::TYPE_UINT+3 == glu::TYPE_UINT_VEC4); DE_STATIC_ASSERT(glu::TYPE_BOOL+1 == glu::TYPE_BOOL_VEC2); DE_STATIC_ASSERT(glu::TYPE_BOOL+2 == glu::TYPE_BOOL_VEC3); DE_STATIC_ASSERT(glu::TYPE_BOOL+3 == glu::TYPE_BOOL_VEC4); DE_ASSERT(testStage); const char* shaderTemplateSrc = "#version ${GLES_VERSION}\n" "precision highp float;\n" "precision highp int;\n" "${DECLARATIONS}\n" "void main()\n" "{\n" " const ${CASE_BASE_TYPE} cval = ${CASE_EXPRESSION};\n" " out0 = cval;\n" " ${OUTPUT}\n" "}\n"; const tcu::StringTemplate shaderTemplate (shaderTemplateSrc); vector ret; for (int caseNdx = 0; caseNdx < numCases; caseNdx++) { std::map shaderTemplateParams; const int minComponents = cases[caseNdx].minComponents; const int maxComponents = cases[caseNdx].maxComponents; const DataType inType = cases[caseNdx].inType; const DataType outType = cases[caseNdx].outType; const string expression = cases[caseNdx].expression; // Check for presence of func(vec, scalar) style specialization, use as gatekeeper for applying said specialization const bool alwaysScalar = expression.find("${MT}")!=string::npos; shaderTemplateParams["GLES_VERSION"] = version == glu::GLSL_VERSION_300_ES ? "300 es" : "100"; shaderTemplateParams["CASE_BASE_TYPE"] = glu::getDataTypeName(outType); shaderTemplateParams["DECLARATIONS"] = "${DECLARATIONS}"; shaderTemplateParams["OUTPUT"] = "${OUTPUT}"; for (int compCount = minComponents-1; compCount < maxComponents; compCount++) { vector children; std::map expressionTemplateParams; string typeName = glu::getDataTypeName((glu::DataType)(inType + compCount)); // results in float, vec2, vec3, vec4 progression (same for other primitive types) const char* componentAccess[] = {"", ".y", ".z", ".w"}; const tcu::StringTemplate expressionTemplate (expression); // Add type to case name if we are generating multiple versions const string caseName = string(cases[caseNdx].name) + (minComponents==maxComponents ? "" : ("_" + typeName)); // ${T} => final type, ${MT} => final type but with scalar version usable even when T is a vector expressionTemplateParams["T"] = typeName; expressionTemplateParams["MT"] = typeName; shaderTemplateParams["CASE_EXPRESSION"] = expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount]; // Add vector access to expression as needed { const string mapped = shaderTemplate.specialize(shaderTemplateParams); if (testStage & SHADER_VERTEX) { glu::sl::ShaderCaseSpecification spec; spec.targetVersion = version; spec.expectResult = glu::sl::EXPECT_PASS; spec.caseType = glu::sl::CASETYPE_VERTEX_ONLY; spec.programs.resize(1); spec.programs[0].sources << glu::VertexSource(mapped); addOutputVar(&spec.values, outType, cases[caseNdx].output); ret.push_back(new ShaderLibraryCase(testContext, renderContext, contextInfo, (caseName + "_vertex").c_str(), "", spec)); } if (testStage & SHADER_FRAGMENT) { glu::sl::ShaderCaseSpecification spec; spec.targetVersion = version; spec.expectResult = glu::sl::EXPECT_PASS; spec.caseType = glu::sl::CASETYPE_FRAGMENT_ONLY; spec.programs.resize(1); spec.programs[0].sources << glu::FragmentSource(mapped); addOutputVar(&spec.values, outType, cases[caseNdx].output); ret.push_back(new ShaderLibraryCase(testContext, renderContext, contextInfo, (caseName + "_fragment").c_str(), "", spec)); } } // Deal with functions that allways accept one ore more scalar parameters even when others are vectors if (alwaysScalar && compCount > 0) { const string scalarCaseName = string(cases[caseNdx].name) + "_" + typeName + "_" + glu::getDataTypeName(inType); expressionTemplateParams["MT"] = glu::getDataTypeName(inType); shaderTemplateParams["CASE_EXPRESSION"] = expressionTemplate.specialize(expressionTemplateParams) + componentAccess[compCount]; { const string mapped = shaderTemplate.specialize(shaderTemplateParams); if (testStage & SHADER_VERTEX) { glu::sl::ShaderCaseSpecification spec; spec.targetVersion = version; spec.expectResult = glu::sl::EXPECT_PASS; spec.caseType = glu::sl::CASETYPE_VERTEX_ONLY; spec.programs.resize(1); spec.programs[0].sources << glu::VertexSource(mapped); addOutputVar(&spec.values, outType, cases[caseNdx].output); ret.push_back(new ShaderLibraryCase(testContext, renderContext, contextInfo, (scalarCaseName + "_vertex").c_str(), "", spec)); } if (testStage & SHADER_FRAGMENT) { glu::sl::ShaderCaseSpecification spec; spec.targetVersion = version; spec.expectResult = glu::sl::EXPECT_PASS; spec.caseType = glu::sl::CASETYPE_FRAGMENT_ONLY; spec.programs.resize(1); spec.programs[0].sources << glu::FragmentSource(mapped); addOutputVar(&spec.values, outType, cases[caseNdx].output); ret.push_back(new ShaderLibraryCase(testContext, renderContext, contextInfo, (scalarCaseName + "_fragment").c_str(), "", spec)); } } } } } return ret; } } // ShaderConstExpr } // gls } // deqp