blob: 5cd9cb6391577195920762d1e3c20ec6b8194c0b [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Copyright (c) 2016 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 loop tests.
*//*--------------------------------------------------------------------*/
#include "vktShaderRenderLoopTests.hpp"
#include "vktShaderRender.hpp"
#include "tcuStringTemplate.hpp"
#include "gluShaderUtil.hpp"
#include "deStringUtil.hpp"
#include <map>
namespace vkt
{
namespace sr
{
namespace
{
static const char* getIntUniformName (int number)
{
switch (number)
{
case 0: return "ui_zero";
case 1: return "ui_one";
case 2: return "ui_two";
case 3: return "ui_three";
case 4: return "ui_four";
case 5: return "ui_five";
case 6: return "ui_six";
case 7: return "ui_seven";
case 8: return "ui_eight";
case 101: return "ui_oneHundredOne";
default:
DE_ASSERT(false);
return "";
}
}
static BaseUniformType getIntUniformType(int number)
{
switch (number)
{
case 1: return UI_ONE;
case 2: return UI_TWO;
case 3: return UI_THREE;
case 4: return UI_FOUR;
case 5: return UI_FIVE;
case 6: return UI_SIX;
case 7: return UI_SEVEN;
case 8: return UI_EIGHT;
default:
DE_ASSERT(false);
return UB_FALSE;
}
}
static const char* getFloatFractionUniformName (int number)
{
switch (number)
{
case 1: return "uf_one";
case 2: return "uf_half";
case 3: return "uf_third";
case 4: return "uf_fourth";
case 5: return "uf_fifth";
case 6: return "uf_sixth";
case 7: return "uf_seventh";
case 8: return "uf_eight";
default:
DE_ASSERT(false);
return "";
}
}
static BaseUniformType getFloatFractionUniformType(int number)
{
switch (number)
{
case 1: return UF_ONE;
case 2: return UF_HALF;
case 3: return UF_THIRD;
case 4: return UF_FOURTH;
case 5: return UF_FIFTH;
case 6: return UF_SIXTH;
case 7: return UF_SEVENTH;
case 8: return UF_EIGHTH;
default:
DE_ASSERT(false);
return UB_FALSE;
}
}
enum LoopType
{
LOOPTYPE_FOR = 0,
LOOPTYPE_WHILE,
LOOPTYPE_DO_WHILE,
LOOPTYPE_LAST
};
static const char* getLoopTypeName (LoopType loopType)
{
static const char* s_names[] =
{
"for",
"while",
"do_while"
};
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
return s_names[(int)loopType];
}
enum LoopCountType
{
LOOPCOUNT_CONSTANT = 0,
LOOPCOUNT_UNIFORM,
LOOPCOUNT_DYNAMIC,
LOOPCOUNT_LAST
};
// Repeated with for, while, do-while. Examples given as 'for' loops.
// Repeated for const, uniform, dynamic loops.
enum LoopCase
{
LOOPCASE_EMPTY_BODY = 0, // for (...) { }
LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; $
LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
LOOPCASE_MIXED_BREAK_CONTINUE,
LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx$
LOOPCASE_101_ITERATIONS, // loop for 101 iterations
LOOPCASE_SEQUENCE, // two loops in sequence
LOOPCASE_NESTED, // two nested loops
LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a th$
LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
LOOPCASE_PRE_FALLTHROUGH, // loop inside switch fallthrough portion
LOOPCASE_POST_FALLTHROUGH, // loop inside switch with fallthrough after
LOOPCASE_DOWHILE_TRAP, // dowhile loop inside loop which shouldn't loop
LOOPCASE_IFBLOCK, // loop inside if block
LOOPCASE_ELSEBLOCK, // loop inside else block
//LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
LOOPCASE_LAST
};
static const char* getLoopCaseName (LoopCase loopCase)
{
static const char* s_names[] =
{
"empty_body",
"infinite_with_unconditional_break_first",
"infinite_with_unconditional_break_last",
"infinite_with_conditional_break",
"single_statement",
"compound_statement",
"sequence_statement",
"no_iterations",
"single_iteration",
"select_iteration_count",
"conditional_continue",
"unconditional_continue",
"only_continue",
"double_continue",
"conditional_break",
"unconditional_break",
"pre_increment",
"post_increment",
"mixed_break_continue",
"vector_counter",
"101_iterations",
"sequence",
"nested",
"nested_sequence",
"nested_tricky_dataflow_1",
"nested_tricky_dataflow_2",
"pre_fallthrough",
"post_fallthrough",
"dowhile_trap",
"ifblock",
"elseblock"
// "multi_declaration",
};
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
return s_names[(int)loopCase];
}
static const char* getLoopCountTypeName (LoopCountType countType)
{
static const char* s_names[] =
{
"constant",
"uniform",
"dynamic"
};
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
return s_names[(int)countType];
}
static void evalLoop0Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
static void evalLoop1Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(1,2,3); }
static void evalLoop2Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(2,3,0); }
static void evalLoop3Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,0,1); }
static ShaderEvalFunc getLoopEvalFunc (int numIters)
{
switch (numIters % 4)
{
case 0: return evalLoop0Iters;
case 1: return evalLoop1Iters;
case 2: return evalLoop2Iters;
case 3: return evalLoop3Iters;
}
DE_FATAL("Invalid loop iteration count.");
return NULL;
}
// ShaderLoop case
class ShaderLoopCase : public ShaderRenderCase
{
public:
ShaderLoopCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
bool isVertexCase,
ShaderEvalFunc evalFunc,
UniformSetup* uniformSetup,
const std::string& vertexShaderSource,
const std::string& fragmentShaderSource)
: ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, uniformSetup, DE_NULL)
{
m_vertShaderSource = vertexShaderSource;
m_fragShaderSource = fragmentShaderSource;
}
};
// Uniform setup tools
class LoopUniformSetup : public UniformSetup
{
public:
LoopUniformSetup (std::vector<BaseUniformType>& types)
: m_uniformInformations(types)
{}
virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
private:
std::vector<BaseUniformType> m_uniformInformations;
};
void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
{
for (size_t i = 0; i < m_uniformInformations.size(); i++)
{
instance.useUniform((deUint32)i, m_uniformInformations[i]);
}
}
// Testcase builders
static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext& testCtx,
const std::string& caseName,
const std::string& description,
bool isVertexCase,
LoopType loopType,
LoopCountType loopCountType,
glu::Precision loopCountPrecision,
glu::DataType loopCountDataType)
{
std::ostringstream vtx;
std::ostringstream frag;
std::ostringstream& op = isVertexCase ? vtx : frag;
vtx << "#version 310 es\n";
frag << "#version 310 es\n";
vtx << "layout(location=0) in highp vec4 a_position;\n";
vtx << "layout(location=1) in highp vec4 a_coords;\n";
frag << "layout(location=0) out mediump vec4 o_color;\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
vtx << "layout(location=3) in mediump float a_one;\n";
if (isVertexCase)
{
vtx << "layout(location=0) out mediump vec3 v_color;\n";
frag << "layout(location=0) in mediump vec3 v_color;\n";
}
else
{
vtx << "layout(location=0) out mediump vec4 v_coords;\n";
frag << "layout(location=0) in mediump vec4 v_coords;\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
{
vtx << "layout(location=1) out mediump float v_one;\n";
frag << "layout(location=1) in mediump float v_one;\n";
}
}
const int numLoopIters = 3;
const bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
deUint32 locationCounter = 0;
std::vector<BaseUniformType> uniformInformations;
if (isIntCounter)
{
if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
{
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
op << "};\n";
uniformInformations.push_back(getIntUniformType(numLoopIters));
locationCounter++;
}
}
else
{
if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
op << " ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
op << "};\n";
uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
locationCounter++;
}
if (numLoopIters != 1){
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
op << " ${COUNTER_PRECISION} float uf_one;\n";
op << "};\n";
uniformInformations.push_back(UF_ONE);
locationCounter++;
}
}
vtx << "\n";
vtx << "void main()\n";
vtx << "{\n";
vtx << " gl_Position = a_position;\n";
frag << "\n";
frag << "void main()\n";
frag << "{\n";
if (isVertexCase)
vtx << " ${PRECISION} vec4 coords = a_coords;\n";
else
frag << " ${PRECISION} vec4 coords = v_coords;\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
{
if (isIntCounter)
{
if (isVertexCase)
vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
else
frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
}
else
{
if (isVertexCase)
vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
else
frag << " ${COUNTER_PRECISION} float one = v_one;\n";
}
}
// Read array.
op << " ${PRECISION} vec4 res = coords;\n";
// Loop iteration count.
std::string iterMaxStr;
if (isIntCounter)
{
if (loopCountType == LOOPCOUNT_CONSTANT)
iterMaxStr = de::toString(numLoopIters);
else if (loopCountType == LOOPCOUNT_UNIFORM)
iterMaxStr = getIntUniformName(numLoopIters);
else if (loopCountType == LOOPCOUNT_DYNAMIC)
iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
else
DE_ASSERT(false);
}
else
{
if (loopCountType == LOOPCOUNT_CONSTANT)
iterMaxStr = "1.0";
else if (loopCountType == LOOPCOUNT_UNIFORM)
iterMaxStr = "uf_one";
else if (loopCountType == LOOPCOUNT_DYNAMIC)
iterMaxStr = "uf_one*one";
else
DE_ASSERT(false);
}
// Loop operations.
std::string initValue = isIntCounter ? "0" : "0.05";
std::string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
std::string loopCmpStr = ("ndx < " + iterMaxStr);
std::string incrementStr;
if (isIntCounter)
incrementStr = "ndx++";
else
{
if (loopCountType == LOOPCOUNT_CONSTANT)
incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
else if (loopCountType == LOOPCOUNT_UNIFORM)
incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
else if (loopCountType == LOOPCOUNT_DYNAMIC)
incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
else
DE_ASSERT(false);
}
// Loop body.
std::string loopBody;
loopBody = " res = res.yzwx + vec4(1.0);\n";
if (loopType == LOOPTYPE_FOR)
{
op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
op << " {\n";
op << loopBody;
op << " }\n";
}
else if (loopType == LOOPTYPE_WHILE)
{
op << "\t" << loopCountDeclStr + ";\n";
op << " while (" + loopCmpStr + ")\n";
op << " {\n";
op << loopBody;
op << "\t\t" + incrementStr + ";\n";
op << " }\n";
}
else if (loopType == LOOPTYPE_DO_WHILE)
{
op << "\t" << loopCountDeclStr + ";\n";
op << " do\n";
op << " {\n";
op << loopBody;
op << "\t\t" + incrementStr + ";\n";
op << " } while (" + loopCmpStr + ");\n";
}
else
DE_ASSERT(false);
op << " res -= vec4(" + de::toString(numLoopIters) + ");\n";
if (isVertexCase)
{
vtx << " v_color = res.rgb;\n";
frag << " o_color = vec4(v_color.rgb, 1.0);\n";
}
else
{
vtx << " v_coords = a_coords;\n";
frag << " o_color = vec4(res.rgb, 1.0);\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
vtx << " v_one = a_one;\n";
}
vtx << "}\n";
frag << "}\n";
// Fill in shader templates.
std::map<std::string, std::string> params;
params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
tcu::StringTemplate vertTemplate(vtx.str());
tcu::StringTemplate fragTemplate(frag.str());
std::string vertexShaderSource = vertTemplate.specialize(params);
std::string fragmentShaderSource = fragTemplate.specialize(params);
// Create the case.
ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
}
static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext& testCtx,
const std::string& caseName,
const std::string& description,
bool isVertexCase,
LoopCase loopCase,
LoopType loopType,
LoopCountType loopCountType)
{
std::ostringstream vtx;
std::ostringstream frag;
std::ostringstream& op = isVertexCase ? vtx : frag;
std::vector<BaseUniformType> uniformInformations;
deUint32 locationCounter = 0;
vtx << "#version 310 es\n";
frag << "#version 310 es\n";
vtx << "layout(location=0) in highp vec4 a_position;\n";
vtx << "layout(location=1) in highp vec4 a_coords;\n";
frag << "layout(location=0) out mediump vec4 o_color;\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
vtx << "layout(location=3) in mediump float a_one;\n";
if (isVertexCase)
{
vtx << "layout(location=0) out mediump vec3 v_color;\n";
frag << "layout(location=0) in mediump vec3 v_color;\n";
}
else
{
vtx << "layout(location=0) out mediump vec4 v_coords;\n";
frag << "layout(location=0) in mediump vec4 v_coords;\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
{
vtx << "layout(location=1) out mediump float v_one;\n";
frag << "layout(location=1) in mediump float v_one;\n";
}
}
if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
op << " bool ub_true;\n";
op << "};\n";
uniformInformations.push_back(UB_TRUE);
locationCounter++;
}
struct
{
char const* name;
BaseUniformType type;
} uniforms[] =
{
{ "ui_zero", UI_ZERO },
{ "ui_one", UI_ONE },
{ "ui_two", UI_TWO },
{ "ui_three", UI_THREE },
{ "ui_four", UI_FOUR },
{ "ui_five", UI_FIVE },
{ "ui_six", UI_SIX },
};
for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
{
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
op << " ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
op << "};\n";
uniformInformations.push_back(uniforms[i].type);
locationCounter++;
}
if (loopCase == LOOPCASE_101_ITERATIONS) {
op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
op << " ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
op << "};\n";
uniformInformations.push_back(UI_ONEHUNDREDONE);
locationCounter++;
}
int iterCount = 3; // value to use in loop
int numIters = 3; // actual number of iterations
vtx << "\n";
vtx << "void main()\n";
vtx << "{\n";
vtx << " gl_Position = a_position;\n";
frag << "\n";
frag << "void main()\n";
frag << "{\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
{
if (isVertexCase)
vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
else
frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
}
if (isVertexCase)
vtx << " ${PRECISION} vec4 coords = a_coords;\n";
else
frag << " ${PRECISION} vec4 coords = v_coords;\n";
// Read array.
op << " ${PRECISION} vec4 res = coords;\n";
// Handle all loop types.
std::string counterPrecisionStr = "mediump";
std::string forLoopStr;
std::string whileLoopStr;
std::string doWhileLoopPreStr;
std::string doWhileLoopPostStr;
if (loopType == LOOPTYPE_FOR)
{
switch (loopCase)
{
case LOOPCASE_EMPTY_BODY:
numIters = 0;
op << " ${FOR_LOOP} {}\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
numIters = 0;
op << " for (;;) { break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
numIters = 1;
op << " for (;;) { res = res.yzwx + vec4(1.0); break; }\n";
break;
case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
numIters = 2;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " for (;;) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
break;
case LOOPCASE_SINGLE_STATEMENT:
op << " ${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_COMPOUND_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${FOR_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_SEQUENCE_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${FOR_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_NO_ITERATIONS:
iterCount = 0;
numIters = 0;
op << " ${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SINGLE_ITERATION:
iterCount = 1;
numIters = 1;
op << " ${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SELECT_ITERATION_COUNT:
op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_CONDITIONAL_CONTINUE:
numIters = iterCount - 1;
op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_UNCONDITIONAL_CONTINUE:
op << " ${FOR_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
break;
case LOOPCASE_ONLY_CONTINUE:
numIters = 0;
op << " ${FOR_LOOP} { continue; }\n";
break;
case LOOPCASE_DOUBLE_CONTINUE:
numIters = iterCount - 1;
op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
break;
case LOOPCASE_CONDITIONAL_BREAK:
numIters = 2;
op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_UNCONDITIONAL_BREAK:
numIters = 1;
op << " ${FOR_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
break;
case LOOPCASE_PRE_INCREMENT:
op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_POST_INCREMENT:
op << " ${FOR_LOOP} { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_MIXED_BREAK_CONTINUE:
numIters = 2;
iterCount = 5;
op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_VECTOR_COUNTER:
op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_101_ITERATIONS:
numIters = iterCount = 101;
op << " ${FOR_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SEQUENCE:
iterCount = 5;
numIters = 5;
op << " ${COUNTER_PRECISION} int i;\n";
op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx + vec4(1.0); }\n";
op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_NESTED:
numIters = 2 * iterCount;
op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
op << " {\n";
op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_SEQUENCE:
numIters = 3 * iterCount;
op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
op << " {\n";
op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
numIters = 2;
op << " ${FOR_LOOP}\n";
op << " {\n";
op << " res = coords; // ignore outer loop effect \n";
op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
numIters = iterCount;
op << " ${FOR_LOOP}\n";
op << " {\n";
op << " res = coords.wxyz - vec4(1.0);\n";
op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " coords = res;\n";
op << " }\n";
break;
case LOOPCASE_PRE_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " case 4:\n";
op << " ${FOR_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_POST_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " ${FOR_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " case 4:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_DOWHILE_TRAP:
numIters = iterCount = 3;
op << " ${FOR_LOOP}\n";
op << " {\n";
op << " do\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } while (i >= ${THREE});\n";
op << " }\n";
break;
case LOOPCASE_IFBLOCK:
numIters = iterCount;
op << " int j = 3;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " ${FOR_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_ELSEBLOCK:
numIters = iterCount;
op << " int j = 2;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " ${FOR_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
default:
DE_ASSERT(false);
}
if (loopCountType == LOOPCOUNT_CONSTANT)
forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
else if (loopCountType == LOOPCOUNT_UNIFORM)
forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
else if (loopCountType == LOOPCOUNT_DYNAMIC)
forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
else
DE_ASSERT(false);
}
else if (loopType == LOOPTYPE_WHILE)
{
switch (loopCase)
{
case LOOPCASE_EMPTY_BODY:
numIters = 0;
op << " ${WHILE_LOOP} {}\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
numIters = 0;
op << " while (true) { break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
numIters = 1;
op << " while (true) { res = res.yzwx + vec4(1.0); break; }\n";
break;
case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
numIters = 2;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (true) { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; }\n";
break;
case LOOPCASE_SINGLE_STATEMENT:
op << " ${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_COMPOUND_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${WHILE_LOOP} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_SEQUENCE_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${WHILE_LOOP} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_NO_ITERATIONS:
iterCount = 0;
numIters = 0;
op << " ${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SINGLE_ITERATION:
iterCount = 1;
numIters = 1;
op << " ${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SELECT_ITERATION_COUNT:
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx + vec4(1.0); i++; }\n";
break;
case LOOPCASE_CONDITIONAL_CONTINUE:
numIters = iterCount - 1;
op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_UNCONDITIONAL_CONTINUE:
op << " ${WHILE_LOOP} { res = res.yzwx + vec4(1.0); continue; }\n";
break;
case LOOPCASE_ONLY_CONTINUE:
numIters = 0;
op << " ${WHILE_LOOP} { continue; }\n";
break;
case LOOPCASE_DOUBLE_CONTINUE:
numIters = iterCount - 1;
op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx + vec4(1.0); continue; }\n";
break;
case LOOPCASE_CONDITIONAL_BREAK:
numIters = 2;
op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_UNCONDITIONAL_BREAK:
numIters = 1;
op << " ${WHILE_LOOP} { res = res.yzwx + vec4(1.0); break; }\n";
break;
case LOOPCASE_PRE_INCREMENT:
numIters = iterCount - 1;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (++i < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_POST_INCREMENT:
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_MIXED_BREAK_CONTINUE:
numIters = 2;
iterCount = 5;
op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); }\n";
break;
case LOOPCASE_VECTOR_COUNTER:
op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
op << " while (i.x < i.z) { res = res.yzwx + vec4(1.0); i.x += i.y; }\n";
break;
case LOOPCASE_101_ITERATIONS:
numIters = iterCount = 101;
op << " ${WHILE_LOOP} res = res.yzwx + vec4(1.0);\n";
break;
case LOOPCASE_SEQUENCE:
iterCount = 6;
numIters = iterCount - 1;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (i++ < ${TWO}) { res = res.yzwx + vec4(1.0); }\n";
op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx + vec4(1.0); }\n"; // \note skips one iteration
break;
case LOOPCASE_NESTED:
numIters = 2 * iterCount;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (i++ < ${TWO})\n";
op << " {\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " while (j++ < ${ITER_COUNT})\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_SEQUENCE:
numIters = 2 * iterCount;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " while (i++ < ${ITER_COUNT})\n";
op << " {\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " while (j++ < ${ONE})\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " while (j++ < ${THREE})\n"; // \note skips one iteration
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
numIters = 2;
op << " ${WHILE_LOOP}\n";
op << " {\n";
op << " res = coords; // ignore outer loop effect \n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " while (j++ < ${TWO})\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
numIters = iterCount;
op << " ${WHILE_LOOP}\n";
op << " {\n";
op << " res = coords.wxyz - vec4(1.0);\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " while (j++ < ${TWO})\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " coords = res;\n";
op << " }\n";
break;
case LOOPCASE_PRE_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " case 4:\n";
op << " ${WHILE_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_POST_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " ${WHILE_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " case 4:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_DOWHILE_TRAP:
numIters = iterCount = 3;
op << " ${WHILE_LOOP}\n";
op << " {\n";
op << " do\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } while (i > ${THREE});\n";
op << " }\n";
break;
case LOOPCASE_IFBLOCK:
numIters = iterCount;
op << " int j = 3;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " ${WHILE_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_ELSEBLOCK:
numIters = iterCount;
op << " int j = 2;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " ${WHILE_LOOP}\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
default:
DE_ASSERT(false);
}
if (loopCountType == LOOPCOUNT_CONSTANT)
whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")";
else if (loopCountType == LOOPCOUNT_UNIFORM)
whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + getIntUniformName(iterCount) + ")";
else if (loopCountType == LOOPCOUNT_DYNAMIC)
whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" + getIntUniformName(iterCount) + ")";
else
DE_ASSERT(false);
}
else
{
DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
switch (loopCase)
{
case LOOPCASE_EMPTY_BODY:
numIters = 0;
op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
numIters = 0;
op << " do { break; res = res.yzwx + vec4(1.0); } while (true);\n";
break;
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
numIters = 1;
op << " do { res = res.yzwx + vec4(1.0); break; } while (true);\n";
break;
case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
numIters = 2;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; i++; } while (true);\n";
break;
case LOOPCASE_SINGLE_STATEMENT:
op << " ${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
break;
case LOOPCASE_COMPOUND_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_SEQUENCE_STATEMENT:
iterCount = 2;
numIters = 2 * iterCount;
op << " ${DO_WHILE_PRE} res = res.yzwx + vec4(1.0), res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
break;
case LOOPCASE_NO_ITERATIONS:
DE_ASSERT(false);
break;
case LOOPCASE_SINGLE_ITERATION:
iterCount = 1;
numIters = 1;
op << " ${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
break;
case LOOPCASE_SELECT_ITERATION_COUNT:
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do { res = res.yzwx + vec4(1.0); } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
break;
case LOOPCASE_CONDITIONAL_CONTINUE:
numIters = iterCount - 1;
op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_UNCONDITIONAL_CONTINUE:
op << " ${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_ONLY_CONTINUE:
numIters = 0;
op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_DOUBLE_CONTINUE:
numIters = iterCount - 1;
op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx + vec4(1.0); continue; } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_CONDITIONAL_BREAK:
numIters = 2;
op << " ${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_UNCONDITIONAL_BREAK:
numIters = 1;
op << " ${DO_WHILE_PRE} { res = res.yzwx + vec4(1.0); break; } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_PRE_INCREMENT:
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
break;
case LOOPCASE_POST_INCREMENT:
numIters = iterCount + 1;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do { res = res.yzwx + vec4(1.0); } while (i++ < ${ITER_COUNT});\n";
break;
case LOOPCASE_MIXED_BREAK_CONTINUE:
numIters = 2;
iterCount = 5;
op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx + vec4(1.0); } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_VECTOR_COUNTER:
op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
op << " do { res = res.yzwx + vec4(1.0); } while ((i.x += i.y) < i.z);\n";
break;
case LOOPCASE_101_ITERATIONS:
numIters = iterCount = 101;
op << " ${DO_WHILE_PRE} res = res.yzwx + vec4(1.0); ${DO_WHILE_POST}\n";
break;
case LOOPCASE_SEQUENCE:
iterCount = 5;
numIters = 5;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do { res = res.yzwx + vec4(1.0); } while (++i < ${TWO});\n";
op << " do { res = res.yzwx + vec4(1.0); } while (++i < ${ITER_COUNT});\n";
break;
case LOOPCASE_NESTED:
numIters = 2 * iterCount;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do\n";
op << " {\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " do\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " while (++j < ${ITER_COUNT});\n";
op << " } while (++i < ${TWO});\n";
break;
case LOOPCASE_NESTED_SEQUENCE:
numIters = 3 * iterCount;
op << " ${COUNTER_PRECISION} int i = 0;\n";
op << " do\n";
op << " {\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " do\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " while (++j < ${TWO});\n";
op << " do\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " while (++j < ${THREE});\n";
op << " } while (++i < ${ITER_COUNT});\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
numIters = 2;
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = coords; // ignore outer loop effect \n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " do\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " while (++j < ${TWO});\n";
op << " } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
numIters = iterCount;
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = coords.wxyz - vec4(1.0);\n";
op << " ${COUNTER_PRECISION} int j = 0;\n";
op << " while (j++ < ${TWO})\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " coords = res;\n";
op << " } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_PRE_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " case 4:\n";
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } ${DO_WHILE_POST}\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_POST_FALLTHROUGH:
numIters = iterCount + 1;
op << " int j = 3;\n";
op << " switch (j)\n";
op << " {\n";
op << " case 3:\n";
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } ${DO_WHILE_POST}\n";
op << " case 4:\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " break;\n";
op << " }\n";
break;
case LOOPCASE_DOWHILE_TRAP:
numIters = iterCount = 3;
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " do\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } while (i >= ${THREE});\n";
op << " } ${DO_WHILE_POST}\n";
break;
case LOOPCASE_IFBLOCK:
numIters = iterCount;
op << " int j = 3;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } ${DO_WHILE_POST}\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
break;
case LOOPCASE_ELSEBLOCK:
numIters = iterCount;
op << " int j = 2;\n";
op << " if (j == ${THREE})\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " }\n";
op << " else\n";
op << " {\n";
op << " ${DO_WHILE_PRE}\n";
op << " {\n";
op << " res = res.yzwx + vec4(1.0);\n";
op << " } ${DO_WHILE_POST}\n";
op << " }\n";
break;
default:
DE_ASSERT(false);
}
doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
if (loopCountType == LOOPCOUNT_CONSTANT)
doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
else if (loopCountType == LOOPCOUNT_UNIFORM)
doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
else if (loopCountType == LOOPCOUNT_DYNAMIC)
doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
else
DE_ASSERT(false);
}
// Shader footers.
op << " res -= vec4(${NUM_ITERS});\n";
if (isVertexCase)
{
vtx << " v_color = res.rgb;\n";
frag << " o_color = vec4(v_color.rgb, 1.0);\n";
}
else
{
vtx << " v_coords = a_coords;\n";
frag << " o_color = vec4(res.rgb, 1.0);\n";
if (loopCountType == LOOPCOUNT_DYNAMIC)
vtx << " v_one = a_one;\n";
}
vtx << "}\n";
frag << "}\n";
// Constants.
std::string oneStr;
std::string twoStr;
std::string threeStr;
std::string iterCountStr;
std::string numItersStr;
numItersStr = de::toString(numIters);
if (loopCountType == LOOPCOUNT_CONSTANT)
{
oneStr = "1";
twoStr = "2";
threeStr = "3";
iterCountStr = de::toString(iterCount);
}
else if (loopCountType == LOOPCOUNT_UNIFORM)
{
oneStr = "ui_one";
twoStr = "ui_two";
threeStr = "ui_three";
iterCountStr = getIntUniformName(iterCount);
}
else if (loopCountType == LOOPCOUNT_DYNAMIC)
{
oneStr = "one*ui_one";
twoStr = "one*ui_two";
threeStr = "one*ui_three";
iterCountStr = std::string("one*") + getIntUniformName(iterCount);
}
else DE_ASSERT(false);
// Fill in shader templates.
std::map<std::string, std::string> params;
params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
params.insert(std::pair<std::string, std::string>("NUM_ITERS", numItersStr));
params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
params.insert(std::pair<std::string, std::string>("ONE", oneStr));
params.insert(std::pair<std::string, std::string>("TWO", twoStr));
params.insert(std::pair<std::string, std::string>("THREE", threeStr));
tcu::StringTemplate vertTemplate(vtx.str());
tcu::StringTemplate fragTemplate(frag.str());
std::string vertexShaderSource = vertTemplate.specialize(params);
std::string fragmentShaderSource = fragTemplate.specialize(params);
// Create the case.
UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
}
class ShaderLoopTests : public tcu::TestCaseGroup
{
public:
ShaderLoopTests (tcu::TestContext& testCtx);
virtual ~ShaderLoopTests (void);
virtual void init (void);
private:
ShaderLoopTests (const ShaderLoopTests&); // not allowed!
ShaderLoopTests& operator= (const ShaderLoopTests&); // not allowed!
};
ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
: TestCaseGroup(testCtx, "loops", "Loop Tests")
{
}
ShaderLoopTests::~ShaderLoopTests (void)
{
}
void ShaderLoopTests::init (void)
{
// Loop cases.
static const glu::ShaderType s_shaderTypes[] =
{
glu::SHADERTYPE_VERTEX,
glu::SHADERTYPE_FRAGMENT
};
static const glu::DataType s_countDataType[] =
{
glu::TYPE_INT,
glu::TYPE_FLOAT
};
TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
addChild(genericGroup);
addChild(specialGroup);
for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
{
const char* loopTypeName = getLoopTypeName((LoopType)loopType);
for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
{
const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
genericGroup->addChild(genericSubGroup);
specialGroup->addChild(specialSubGroup);
// Generic cases.
for (int precision = glu::PRECISION_MEDIUMP; precision < glu::PRECISION_LAST; precision++)
{
const char* precisionName = getPrecisionName((glu::Precision)precision);
for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
{
glu::DataType loopDataType = s_countDataType[dataTypeNdx];
const char* dataTypeName = getDataTypeName(loopDataType);
for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
{
glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
const char* shaderTypeName = getShaderTypeName(shaderType);
bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
genericSubGroup->addChild(testCase.release());
}
}
}
// Special cases.
for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
{
const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
// no-iterations not possible with do-while.
if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
continue;
for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
{
glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
const char* shaderTypeName = getShaderTypeName(shaderType);
bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
specialSubGroup->addChild(testCase.release());
}
}
}
}
}
} // anonymous
tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
{
return new ShaderLoopTests(testCtx);
}
} // sr
} // vkt