You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
462 lines
13 KiB
462 lines
13 KiB
/*------------------------------------------------------------------------- |
|
* drawElements Quality Program OpenGL ES 3.0 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 Shader switch statement tests. |
|
* |
|
* Variables: |
|
* + Selection expression type: static, uniform, dynamic |
|
* + Switch layout - fall-through or use of default label |
|
* + Switch nested in loop/conditional statement |
|
* + Loop/conditional statement nested in switch |
|
*//*--------------------------------------------------------------------*/ |
|
|
|
#include "es3fShaderSwitchTests.hpp" |
|
#include "glsShaderRenderCase.hpp" |
|
#include "glsShaderLibrary.hpp" |
|
#include "tcuStringTemplate.hpp" |
|
#include "deMath.h" |
|
|
|
namespace deqp |
|
{ |
|
namespace gles3 |
|
{ |
|
namespace Functional |
|
{ |
|
|
|
using namespace deqp::gls; |
|
using std::string; |
|
using std::map; |
|
using std::vector; |
|
|
|
class ShaderSwitchCase : public ShaderRenderCase |
|
{ |
|
public: |
|
ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc); |
|
virtual ~ShaderSwitchCase (void); |
|
}; |
|
|
|
ShaderSwitchCase::ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc) |
|
: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc) |
|
{ |
|
m_vertShaderSource = vtxSource; |
|
m_fragShaderSource = fragSource; |
|
} |
|
|
|
ShaderSwitchCase::~ShaderSwitchCase (void) |
|
{ |
|
} |
|
|
|
enum SwitchType |
|
{ |
|
SWITCHTYPE_STATIC = 0, |
|
SWITCHTYPE_UNIFORM, |
|
SWITCHTYPE_DYNAMIC, |
|
|
|
SWITCHTYPE_LAST |
|
}; |
|
|
|
static void evalSwitchStatic (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); } |
|
static void evalSwitchUniform (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); } |
|
static void evalSwitchDynamic (ShaderEvalContext& evalCtx) |
|
{ |
|
switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f))) |
|
{ |
|
case 0: evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2); break; |
|
case 1: evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1); break; |
|
case 2: evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); break; |
|
case 3: evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0); break; |
|
default: evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0); break; |
|
} |
|
} |
|
|
|
static tcu::TestCase* makeSwitchCase (Context& context, const char* name, const char* desc, SwitchType type, bool isVertex, const LineStream& switchBody) |
|
{ |
|
std::ostringstream vtx; |
|
std::ostringstream frag; |
|
std::ostringstream& op = isVertex ? vtx : frag; |
|
|
|
vtx << "#version 300 es\n" |
|
<< "in highp vec4 a_position;\n" |
|
<< "in highp vec4 a_coords;\n"; |
|
frag << "#version 300 es\n" |
|
<< "layout(location = 0) out mediump vec4 o_color;\n"; |
|
|
|
if (isVertex) |
|
{ |
|
vtx << "out mediump vec4 v_color;\n"; |
|
frag << "in mediump vec4 v_color;\n"; |
|
} |
|
else |
|
{ |
|
vtx << "out highp vec4 v_coords;\n"; |
|
frag << "in highp vec4 v_coords;\n"; |
|
} |
|
|
|
if (type == SWITCHTYPE_UNIFORM) |
|
op << "uniform highp int ui_two;\n"; |
|
|
|
vtx << "\n" |
|
<< "void main (void)\n" |
|
<< "{\n" |
|
<< " gl_Position = a_position;\n"; |
|
frag << "\n" |
|
<< "void main (void)\n" |
|
<< "{\n"; |
|
|
|
// Setup. |
|
op << " highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n"; |
|
op << " mediump vec3 res = vec3(0.0);\n\n"; |
|
|
|
// Switch body. |
|
map<string, string> params; |
|
params["CONDITION"] = type == SWITCHTYPE_STATIC ? "2" : |
|
type == SWITCHTYPE_UNIFORM ? "ui_two" : |
|
type == SWITCHTYPE_DYNAMIC ? "int(floor(coords.z*1.5 + 2.0))" : "???"; |
|
|
|
op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str(); |
|
op << "\n"; |
|
|
|
if (isVertex) |
|
{ |
|
vtx << " v_color = vec4(res, 1.0);\n"; |
|
frag << " o_color = v_color;\n"; |
|
} |
|
else |
|
{ |
|
vtx << " v_coords = a_coords;\n"; |
|
frag << " o_color = vec4(res, 1.0);\n"; |
|
} |
|
|
|
vtx << "}\n"; |
|
frag << "}\n"; |
|
|
|
return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(), |
|
type == SWITCHTYPE_STATIC ? evalSwitchStatic : |
|
type == SWITCHTYPE_UNIFORM ? evalSwitchUniform : |
|
type == SWITCHTYPE_DYNAMIC ? evalSwitchDynamic : (ShaderEvalFunc)DE_NULL); |
|
} |
|
|
|
static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody) |
|
{ |
|
static const char* switchTypeNames[] = { "static", "uniform", "dynamic" }; |
|
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST); |
|
|
|
for (int type = 0; type < SWITCHTYPE_LAST; type++) |
|
{ |
|
group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(), desc, (SwitchType)type, true, switchBody)); |
|
group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(), desc, (SwitchType)type, false, switchBody)); |
|
} |
|
} |
|
|
|
ShaderSwitchTests::ShaderSwitchTests (Context& context) |
|
: TestCaseGroup(context, "switch", "Switch statement tests") |
|
{ |
|
} |
|
|
|
ShaderSwitchTests::~ShaderSwitchTests (void) |
|
{ |
|
} |
|
|
|
void ShaderSwitchTests::init (void) |
|
{ |
|
// Expected swizzles: |
|
// 0: xyz |
|
// 1: wzy |
|
// 2: yzw |
|
// 3: zyx |
|
|
|
makeSwitchCases(this, "basic", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: res = coords.yzw; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "const_expr_in_label", "Constant expression in label", |
|
LineStream(1) |
|
<< "const int t = 2;" |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case int(0.0): res = coords.xyz; break;" |
|
<< " case 2-1: res = coords.wzy; break;" |
|
<< " case 3&(1<<1): res = coords.yzw; break;" |
|
<< " case t+1: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "default_label", "Default label usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " default: res = coords.yzw;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "default_not_last", "Default label usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " default: res = coords.yzw; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "no_default_label", "No match in switch without default label", |
|
LineStream(1) |
|
<< "res = coords.yzw;\n" |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "fall_through", "Fall-through", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: coords = coords.yzwx;" |
|
<< " case 4: res = vec3(coords); break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "fall_through_default", "Fall-through", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " case 2: coords = coords.yzwx;" |
|
<< " default: res = vec3(coords);" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "conditional_fall_through", "Fall-through", |
|
LineStream(1) |
|
<< "highp vec4 tmp = coords;" |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2:" |
|
<< " tmp = coords.yzwx;" |
|
<< " case 3:" |
|
<< " res = vec3(tmp);" |
|
<< " if (${CONDITION} != 3)" |
|
<< " break;" |
|
<< " default: res = tmp.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "conditional_fall_through_2", "Fall-through", |
|
LineStream(1) |
|
<< "highp vec4 tmp = coords;" |
|
<< "mediump int c = ${CONDITION};" |
|
<< "switch (c)" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2:" |
|
<< " c += ${CONDITION};" |
|
<< " tmp = coords.yzwx;" |
|
<< " case 3:" |
|
<< " res = vec3(tmp);" |
|
<< " if (c == 4)" |
|
<< " break;" |
|
<< " default: res = tmp.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "scope", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2:" |
|
<< " {" |
|
<< " mediump vec3 t = coords.yzw;" |
|
<< " res = t;" |
|
<< " break;" |
|
<< " }" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "switch_in_if", "Switch in for loop", |
|
LineStream(1) |
|
<< "if (${CONDITION} >= 0)" |
|
<< "{" |
|
<< " switch (${CONDITION})" |
|
<< " {" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: res = coords.yzw; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " }" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop", |
|
LineStream(1) |
|
<< "for (int i = 0; i <= ${CONDITION}; i++)" |
|
<< "{" |
|
<< " switch (i)" |
|
<< " {" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: res = coords.yzw; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " }" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop", |
|
LineStream(1) |
|
<< "int i = 0;" |
|
<< "while (i <= ${CONDITION})" |
|
<< "{" |
|
<< " switch (i)" |
|
<< " {" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: res = coords.yzw; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " }" |
|
<< " i += 1;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop", |
|
LineStream(1) |
|
<< "int i = 0;" |
|
<< "do" |
|
<< "{" |
|
<< " switch (i)" |
|
<< " {" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " case 2: res = coords.yzw; break;" |
|
<< " case 3: res = coords.zyx; break;" |
|
<< " }" |
|
<< " i += 1;" |
|
<< "} while (i <= ${CONDITION});"); |
|
|
|
makeSwitchCases(this, "if_in_switch", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1: res = coords.wzy; break;" |
|
<< " default:" |
|
<< " if (${CONDITION} == 2)" |
|
<< " res = coords.yzw;" |
|
<< " else" |
|
<< " res = coords.zyx;" |
|
<< " break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1:" |
|
<< " case 2:" |
|
<< " {" |
|
<< " highp vec3 t = coords.yzw;" |
|
<< " for (int i = 0; i < ${CONDITION}; i++)" |
|
<< " t = t.zyx;" |
|
<< " res = t;" |
|
<< " break;" |
|
<< " }" |
|
<< " default: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1:" |
|
<< " case 2:" |
|
<< " {" |
|
<< " highp vec3 t = coords.yzw;" |
|
<< " int i = 0;" |
|
<< " while (i < ${CONDITION})" |
|
<< " {" |
|
<< " t = t.zyx;" |
|
<< " i += 1;" |
|
<< " }" |
|
<< " res = t;" |
|
<< " break;" |
|
<< " }" |
|
<< " default: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1:" |
|
<< " case 2:" |
|
<< " {" |
|
<< " highp vec3 t = coords.yzw;" |
|
<< " int i = 0;" |
|
<< " do" |
|
<< " {" |
|
<< " t = t.zyx;" |
|
<< " i += 1;" |
|
<< " } while (i < ${CONDITION});" |
|
<< " res = t;" |
|
<< " break;" |
|
<< " }" |
|
<< " default: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage", |
|
LineStream(1) |
|
<< "switch (${CONDITION})" |
|
<< "{" |
|
<< " case 0: res = coords.xyz; break;" |
|
<< " case 1:" |
|
<< " case 2:" |
|
<< " switch (${CONDITION} - 1)" |
|
<< " {" |
|
<< " case 0: res = coords.wzy; break;" |
|
<< " case 1: res = coords.yzw; break;" |
|
<< " }" |
|
<< " break;" |
|
<< " default: res = coords.zyx; break;" |
|
<< "}"); |
|
|
|
// Negative cases. |
|
ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo()); |
|
vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test"); |
|
|
|
for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++) |
|
addChild(*i); |
|
} |
|
|
|
} // Functional |
|
} // gles3 |
|
} // deqp
|
|
|