/*-------------------------------------------------------------------------
* 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<tcu::TestNode*> 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<tcu::TestNode*> ret;
for (int caseNdx = 0; caseNdx < numCases; caseNdx++)
{
std::map<string, string> 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<tcu::TestNode*> children;
std::map<string, string> 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