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.
1349 lines
39 KiB
1349 lines
39 KiB
/*------------------------------------------------------------------------- |
|
* drawElements Quality Program OpenGL ES 2.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 loop tests. |
|
* |
|
* \todo [petri] |
|
* - loop body cases (do different operations inside the loops) |
|
* - more complex nested loops |
|
* * random generated? |
|
* * dataflow variations |
|
* * mixed loop types |
|
* - |
|
*//*--------------------------------------------------------------------*/ |
|
|
|
#include "es2fShaderLoopTests.hpp" |
|
#include "glsShaderLibrary.hpp" |
|
#include "glsShaderRenderCase.hpp" |
|
#include "gluShaderUtil.hpp" |
|
#include "tcuStringTemplate.hpp" |
|
|
|
#include "deStringUtil.hpp" |
|
#include "deInt32.h" |
|
#include "deMemory.h" |
|
|
|
#include <map> |
|
|
|
using namespace std; |
|
using namespace tcu; |
|
using namespace glu; |
|
using namespace deqp::gls; |
|
|
|
namespace deqp |
|
{ |
|
namespace gles2 |
|
{ |
|
namespace Functional |
|
{ |
|
|
|
// 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>; continue; } |
|
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.x += ndx.z) { ... } |
|
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 third |
|
LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow |
|
LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow |
|
LOOPCASE_CONDITIONAL_BODY, // conditional body in loop |
|
LOOPCASE_FUNCTION_CALL_RETURN, // function call in loop with return value usage |
|
LOOPCASE_FUNCTION_CALL_INOUT, // function call with inout parameter usage |
|
|
|
LOOPCASE_LAST |
|
}; |
|
|
|
enum LoopRequirement |
|
{ |
|
LOOPREQUIREMENT_STANDARD = 0, //!< Minimum requirements by standard (constant for loop with simple iterator). |
|
LOOPREQUIREMENT_UNIFORM, |
|
LOOPREQUIREMENT_DYNAMIC, |
|
|
|
LOOPREQUIREMENT_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", |
|
"conditional_body", |
|
"function_call_return", |
|
"function_call_inout" |
|
}; |
|
|
|
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST); |
|
DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST)); |
|
return s_names[(int)loopCase]; |
|
} |
|
|
|
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 |
|
}; |
|
|
|
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; |
|
} |
|
|
|
// ShaderLoopCase |
|
|
|
class ShaderLoopCase : public ShaderRenderCase |
|
{ |
|
public: |
|
ShaderLoopCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, LoopRequirement requirement, const char* vertShaderSource, const char* fragShaderSource); |
|
virtual ~ShaderLoopCase (void); |
|
|
|
void init (void); |
|
|
|
private: |
|
ShaderLoopCase (const ShaderLoopCase&); // not allowed! |
|
ShaderLoopCase& operator= (const ShaderLoopCase&); // not allowed! |
|
|
|
virtual void setup (int programID); |
|
virtual void setupUniforms (int programID, const Vec4& constCoords); |
|
|
|
LoopRequirement m_requirement; |
|
}; |
|
|
|
ShaderLoopCase::ShaderLoopCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, LoopRequirement requirement, const char* vertShaderSource, const char* fragShaderSource) |
|
: ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc) |
|
, m_requirement (requirement) |
|
{ |
|
m_vertShaderSource = vertShaderSource; |
|
m_fragShaderSource = fragShaderSource; |
|
} |
|
|
|
ShaderLoopCase::~ShaderLoopCase (void) |
|
{ |
|
} |
|
|
|
void ShaderLoopCase::init (void) |
|
{ |
|
bool isSupported = true; |
|
|
|
if (m_requirement == LOOPREQUIREMENT_UNIFORM) |
|
isSupported = m_isVertexCase ? m_ctxInfo.isVertexUniformLoopSupported() |
|
: m_ctxInfo.isFragmentUniformLoopSupported(); |
|
else if (m_requirement == LOOPREQUIREMENT_DYNAMIC) |
|
isSupported = m_isVertexCase ? m_ctxInfo.isVertexDynamicLoopSupported() |
|
: m_ctxInfo.isFragmentDynamicLoopSupported(); |
|
|
|
try |
|
{ |
|
ShaderRenderCase::init(); |
|
} |
|
catch (const CompileFailed&) |
|
{ |
|
if (!isSupported) |
|
throw tcu::NotSupportedError("Loop type is not supported"); |
|
else |
|
throw; |
|
} |
|
} |
|
|
|
void ShaderLoopCase::setup (int programID) |
|
{ |
|
DE_UNREF(programID); |
|
} |
|
|
|
void ShaderLoopCase::setupUniforms (int programID, const Vec4& constCoords) |
|
{ |
|
DE_UNREF(programID); |
|
DE_UNREF(constCoords); |
|
} |
|
|
|
// Test case creation. |
|
|
|
static ShaderLoopCase* createGenericLoopCase (Context& context, const char* caseName, const char* description, bool isVertexCase, LoopType loopType, LoopCountType loopCountType, Precision loopCountPrecision, DataType loopCountDataType) |
|
{ |
|
std::ostringstream vtx; |
|
std::ostringstream frag; |
|
std::ostringstream& op = isVertexCase ? vtx : frag; |
|
|
|
vtx << "attribute highp vec4 a_position;\n"; |
|
vtx << "attribute highp vec4 a_coords;\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
vtx << "attribute mediump float a_one;\n"; |
|
|
|
if (isVertexCase) |
|
{ |
|
vtx << "varying mediump vec3 v_color;\n"; |
|
frag << "varying mediump vec3 v_color;\n"; |
|
} |
|
else |
|
{ |
|
vtx << "varying mediump vec4 v_coords;\n"; |
|
frag << "varying mediump vec4 v_coords;\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
{ |
|
vtx << "varying mediump float v_one;\n"; |
|
frag << "varying mediump float v_one;\n"; |
|
} |
|
} |
|
|
|
// \todo [petri] Pass numLoopIters from outside? |
|
int numLoopIters = 3; |
|
bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType); |
|
|
|
if (isIntCounter) |
|
{ |
|
if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC) |
|
op << "uniform ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n"; |
|
} |
|
else |
|
{ |
|
if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC) |
|
op << "uniform ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n"; |
|
|
|
if (numLoopIters != 1) |
|
op << "uniform ${COUNTER_PRECISION} float uf_one;\n"; |
|
} |
|
|
|
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. |
|
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 = 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. |
|
string initValue = isIntCounter ? "0" : "0.05"; |
|
string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue; |
|
string loopCmpStr = ("ndx < " + iterMaxStr); |
|
string incrementStr; |
|
if (isIntCounter) |
|
incrementStr = "ndx++"; |
|
else |
|
{ |
|
if (loopCountType == LOOPCOUNT_CONSTANT) |
|
incrementStr = string("ndx += ") + de::toString(1.0f / (float)numLoopIters); |
|
else if (loopCountType == LOOPCOUNT_UNIFORM) |
|
incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters); |
|
else if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one"; |
|
else |
|
DE_ASSERT(false); |
|
} |
|
|
|
// Loop body. |
|
string loopBody; |
|
|
|
loopBody = " res = res.yzwx;\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); |
|
|
|
if (isVertexCase) |
|
{ |
|
vtx << " v_color = res.rgb;\n"; |
|
frag << " gl_FragColor = vec4(v_color.rgb, 1.0);\n"; |
|
} |
|
else |
|
{ |
|
vtx << " v_coords = a_coords;\n"; |
|
frag << " gl_FragColor = vec4(res.rgb, 1.0);\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
vtx << " v_one = a_one;\n"; |
|
} |
|
|
|
vtx << "}\n"; |
|
frag << "}\n"; |
|
|
|
// Fill in shader templates. |
|
map<string, string> params; |
|
params.insert(pair<string, string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType))); |
|
params.insert(pair<string, string>("PRECISION", "mediump")); |
|
params.insert(pair<string, string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision))); |
|
|
|
StringTemplate vertTemplate(vtx.str().c_str()); |
|
StringTemplate fragTemplate(frag.str().c_str()); |
|
string vertexShaderSource = vertTemplate.specialize(params); |
|
string fragmentShaderSource = fragTemplate.specialize(params); |
|
|
|
// Create the case. |
|
ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters); |
|
LoopRequirement requirement; |
|
|
|
if (loopType == LOOPTYPE_FOR) |
|
{ |
|
if (loopCountType == LOOPCOUNT_CONSTANT) |
|
requirement = LOOPREQUIREMENT_STANDARD; |
|
else if (loopCountType == LOOPCOUNT_UNIFORM) |
|
requirement = LOOPREQUIREMENT_UNIFORM; |
|
else |
|
requirement = LOOPREQUIREMENT_DYNAMIC; |
|
} |
|
else |
|
requirement = LOOPREQUIREMENT_DYNAMIC; |
|
|
|
return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, requirement, vertexShaderSource.c_str(), fragmentShaderSource.c_str()); |
|
} |
|
|
|
// \todo [petri] Generalize to float as well? |
|
static ShaderLoopCase* createSpecialLoopCase (Context& context, const char* caseName, const char* description, bool isVertexCase, LoopCase loopCase, LoopType loopType, LoopCountType loopCountType) |
|
{ |
|
std::ostringstream vtx; |
|
std::ostringstream frag; |
|
std::ostringstream& op = isVertexCase ? vtx : frag; |
|
|
|
vtx << "attribute highp vec4 a_position;\n"; |
|
vtx << "attribute highp vec4 a_coords;\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
vtx << "attribute mediump float a_one;\n"; |
|
|
|
// Attribute and varyings. |
|
if (isVertexCase) |
|
{ |
|
vtx << "varying mediump vec3 v_color;\n"; |
|
frag << "varying mediump vec3 v_color;\n"; |
|
} |
|
else |
|
{ |
|
vtx << "varying mediump vec4 v_coords;\n"; |
|
frag << "varying mediump vec4 v_coords;\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
{ |
|
vtx << "varying mediump float v_one;\n"; |
|
frag << "varying mediump float v_one;\n"; |
|
} |
|
} |
|
|
|
if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) |
|
op << "uniform bool ub_true;\n"; |
|
|
|
op << "uniform ${COUNTER_PRECISION} int ui_zero, ui_one, ui_two, ui_three, ui_four, ui_five, ui_six;\n"; |
|
if (loopCase == LOOPCASE_101_ITERATIONS) |
|
op << "uniform ${COUNTER_PRECISION} int ui_oneHundredOne;\n"; |
|
|
|
int iterCount = 3; // value to use in loop |
|
int numIters = 3; // actual number of iterations |
|
|
|
// Generate helpers if necessary. |
|
if (loopCase == LOOPCASE_FUNCTION_CALL_RETURN) |
|
op << "\n${PRECISION} vec4 func (in ${PRECISION} vec4 coords) { return coords.yzwx; }\n"; |
|
else if (loopCase == LOOPCASE_FUNCTION_CALL_INOUT) |
|
op << "\nvoid func (inout ${PRECISION} vec4 coords) { coords = coords.yzwx; }\n"; |
|
|
|
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. |
|
string counterPrecisionStr = "mediump"; |
|
string forLoopStr; |
|
string whileLoopStr; |
|
string doWhileLoopPreStr; |
|
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; }\n"; |
|
break; |
|
|
|
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST: |
|
numIters = 1; |
|
op << " for (;;) { res = res.yzwx; break; }\n"; |
|
break; |
|
|
|
case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK: |
|
numIters = 2; |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n"; |
|
break; |
|
|
|
case LOOPCASE_SINGLE_STATEMENT: |
|
op << " ${FOR_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_COMPOUND_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_SEQUENCE_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_NO_ITERATIONS: |
|
iterCount = 0; |
|
numIters = 0; |
|
op << " ${FOR_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_SINGLE_ITERATION: |
|
iterCount = 1; |
|
numIters = 1; |
|
op << " ${FOR_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_SELECT_ITERATION_COUNT: |
|
op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_CONTINUE: |
|
numIters = iterCount - 1; |
|
op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_CONTINUE: |
|
op << " ${FOR_LOOP} { res = res.yzwx; 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; continue; }\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BREAK: |
|
numIters = 2; |
|
op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_BREAK: |
|
numIters = 1; |
|
op << " ${FOR_LOOP} { res = res.yzwx; break; }\n"; |
|
break; |
|
|
|
case LOOPCASE_PRE_INCREMENT: |
|
op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_POST_INCREMENT: |
|
op << " ${FOR_LOOP} { res = res.yzwx; }\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; }\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; }\n"; |
|
break; |
|
|
|
case LOOPCASE_101_ITERATIONS: |
|
numIters = iterCount = 101; |
|
op << " ${FOR_LOOP} res = res.yzwx;\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; }\n"; |
|
op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\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;\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;\n"; |
|
op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n"; |
|
op << " res = res.yzwx;\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;\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_NESTED_TRICKY_DATAFLOW_2: |
|
numIters = iterCount; |
|
op << " ${FOR_LOOP}\n"; |
|
op << " {\n"; |
|
op << " res = coords.wxyz;\n"; |
|
op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n"; |
|
op << " res = res.yzwx;\n"; |
|
op << " coords = res;\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BODY: |
|
numIters = de::min(2, iterCount); |
|
op << " ${FOR_LOOP} if (i < 2) res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_RETURN: |
|
numIters = iterCount; |
|
op << " ${FOR_LOOP}\n"; |
|
op << " {\n"; |
|
op << " res = func(res);\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_INOUT: |
|
numIters = iterCount; |
|
op << " ${FOR_LOOP}\n"; |
|
op << " {\n"; |
|
op << " func(res);\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
default: |
|
DE_ASSERT(false); |
|
} |
|
|
|
if (loopCountType == LOOPCOUNT_CONSTANT) |
|
forLoopStr = string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)"; |
|
else if (loopCountType == LOOPCOUNT_UNIFORM) |
|
forLoopStr = string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)"; |
|
else if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
forLoopStr = 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; }\n"; |
|
break; |
|
|
|
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST: |
|
numIters = 1; |
|
op << " while (true) { res = res.yzwx; break; }\n"; |
|
break; |
|
|
|
case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK: |
|
numIters = 2; |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n"; |
|
break; |
|
|
|
case LOOPCASE_SINGLE_STATEMENT: |
|
op << " ${WHILE_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_COMPOUND_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_SEQUENCE_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_NO_ITERATIONS: |
|
iterCount = 0; |
|
numIters = 0; |
|
op << " ${WHILE_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_SINGLE_ITERATION: |
|
iterCount = 1; |
|
numIters = 1; |
|
op << " ${WHILE_LOOP} res = res.yzwx;\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; i++; }\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_CONTINUE: |
|
numIters = iterCount - 1; |
|
op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_CONTINUE: |
|
op << " ${WHILE_LOOP} { res = res.yzwx; 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; continue; }\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BREAK: |
|
numIters = 2; |
|
op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_BREAK: |
|
numIters = 1; |
|
op << " ${WHILE_LOOP} { res = res.yzwx; 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; }\n"; |
|
break; |
|
|
|
case LOOPCASE_POST_INCREMENT: |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\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; }\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; i.x += i.y; }\n"; |
|
break; |
|
|
|
case LOOPCASE_101_ITERATIONS: |
|
numIters = iterCount = 101; |
|
op << " ${WHILE_LOOP} res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_SEQUENCE: |
|
iterCount = 6; |
|
numIters = iterCount - 1; |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " while (i++ < ${TWO}) { res = res.yzwx; }\n"; |
|
op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\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;\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;\n"; |
|
op << " while (j++ < ${THREE})\n"; // \note skips one iteration |
|
op << " res = res.yzwx;\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;\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_NESTED_TRICKY_DATAFLOW_2: |
|
numIters = iterCount; |
|
op << " ${WHILE_LOOP}\n"; |
|
op << " {\n"; |
|
op << " res = coords.wxyz;\n"; |
|
op << " ${COUNTER_PRECISION} int j = 0;\n"; |
|
op << " while (j++ < ${TWO})\n"; |
|
op << " res = res.yzwx;\n"; |
|
op << " coords = res;\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BODY: |
|
numIters = de::min(1, iterCount); |
|
op << " ${WHILE_LOOP} if (i < 2) res = res.yzwx;\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_RETURN: |
|
numIters = iterCount; |
|
op << " ${WHILE_LOOP}\n"; |
|
op << " {\n"; |
|
op << " res = func(res);\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_INOUT: |
|
numIters = iterCount; |
|
op << " ${WHILE_LOOP}\n"; |
|
op << " {\n"; |
|
op << " func(res);\n"; |
|
op << " }\n"; |
|
break; |
|
|
|
default: |
|
DE_ASSERT(false); |
|
} |
|
|
|
if (loopCountType == LOOPCOUNT_CONSTANT) |
|
whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")"; |
|
else if (loopCountType == LOOPCOUNT_UNIFORM) |
|
whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + getIntUniformName(iterCount) + ")"; |
|
else if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
whileLoopStr = 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; } while (true);\n"; |
|
break; |
|
|
|
case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST: |
|
numIters = 1; |
|
op << " do { res = res.yzwx; 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; if (i == ${ONE}) break; i++; } while (true);\n"; |
|
break; |
|
|
|
case LOOPCASE_SINGLE_STATEMENT: |
|
op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_COMPOUND_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_SEQUENCE_STATEMENT: |
|
iterCount = 2; |
|
numIters = 2 * iterCount; |
|
op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${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; ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_SELECT_ITERATION_COUNT: |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " do { res = res.yzwx; } 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; } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_CONTINUE: |
|
op << " ${DO_WHILE_PRE} { res = res.yzwx; 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; continue; } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BREAK: |
|
numIters = 2; |
|
op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_UNCONDITIONAL_BREAK: |
|
numIters = 1; |
|
op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_PRE_INCREMENT: |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " do { res = res.yzwx; } 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; } 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; } ${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; } while ((i.x += i.y) < i.z);\n"; |
|
break; |
|
|
|
case LOOPCASE_101_ITERATIONS: |
|
numIters = iterCount = 101; |
|
op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_SEQUENCE: |
|
iterCount = 5; |
|
numIters = 5; |
|
op << " ${COUNTER_PRECISION} int i = 0;\n"; |
|
op << " do { res = res.yzwx; } while (++i < ${TWO});\n"; |
|
op << " do { res = res.yzwx; } 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;\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;\n"; |
|
op << " while (++j < ${TWO});\n"; |
|
op << " do\n"; |
|
op << " res = res.yzwx;\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;\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;\n"; |
|
op << " ${COUNTER_PRECISION} int j = 0;\n"; |
|
op << " while (j++ < ${TWO})\n"; |
|
op << " res = res.yzwx;\n"; |
|
op << " coords = res;\n"; |
|
op << " } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_CONDITIONAL_BODY: |
|
numIters = de::min(2, iterCount); |
|
op << " ${DO_WHILE_PRE} if (i < 2) res = res.yzwx; ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_RETURN: |
|
numIters = iterCount; |
|
op << " ${DO_WHILE_PRE}\n"; |
|
op << " {\n"; |
|
op << " res = func(res);\n"; |
|
op << " } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
case LOOPCASE_FUNCTION_CALL_INOUT: |
|
numIters = iterCount; |
|
op << " ${DO_WHILE_PRE}\n"; |
|
op << " {\n"; |
|
op << " func(res);\n"; |
|
op << " } ${DO_WHILE_POST}\n"; |
|
break; |
|
|
|
default: |
|
DE_ASSERT(false); |
|
} |
|
|
|
doWhileLoopPreStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo "; |
|
if (loopCountType == LOOPCOUNT_CONSTANT) |
|
doWhileLoopPostStr = string(" while (++i < ") + de::toString(iterCount) + ");\n"; |
|
else if (loopCountType == LOOPCOUNT_UNIFORM) |
|
doWhileLoopPostStr = string(" while (++i < ") + getIntUniformName(iterCount) + ");\n"; |
|
else if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
doWhileLoopPostStr = string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n"; |
|
else |
|
DE_ASSERT(false); |
|
} |
|
|
|
// Shader footers. |
|
if (isVertexCase) |
|
{ |
|
vtx << " v_color = res.rgb;\n"; |
|
frag << " gl_FragColor = vec4(v_color.rgb, 1.0);\n"; |
|
} |
|
else |
|
{ |
|
vtx << " v_coords = a_coords;\n"; |
|
frag << " gl_FragColor = vec4(res.rgb, 1.0);\n"; |
|
|
|
if (loopCountType == LOOPCOUNT_DYNAMIC) |
|
vtx << " v_one = a_one;\n"; |
|
} |
|
|
|
vtx << "}\n"; |
|
frag << "}\n"; |
|
|
|
// Constants. |
|
string oneStr; |
|
string twoStr; |
|
string threeStr; |
|
string iterCountStr; |
|
|
|
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 = string("one*") + getIntUniformName(iterCount); |
|
} |
|
else DE_ASSERT(false); |
|
|
|
// Fill in shader templates. |
|
map<string, string> params; |
|
params.insert(pair<string, string>("PRECISION", "mediump")); |
|
params.insert(pair<string, string>("ITER_COUNT", iterCountStr)); |
|
params.insert(pair<string, string>("COUNTER_PRECISION", counterPrecisionStr)); |
|
params.insert(pair<string, string>("FOR_LOOP", forLoopStr)); |
|
params.insert(pair<string, string>("WHILE_LOOP", whileLoopStr)); |
|
params.insert(pair<string, string>("DO_WHILE_PRE", doWhileLoopPreStr)); |
|
params.insert(pair<string, string>("DO_WHILE_POST", doWhileLoopPostStr)); |
|
params.insert(pair<string, string>("ONE", oneStr)); |
|
params.insert(pair<string, string>("TWO", twoStr)); |
|
params.insert(pair<string, string>("THREE", threeStr)); |
|
|
|
StringTemplate vertTemplate(vtx.str().c_str()); |
|
StringTemplate fragTemplate(frag.str().c_str()); |
|
string vertexShaderSource = vertTemplate.specialize(params); |
|
string fragmentShaderSource = fragTemplate.specialize(params); |
|
|
|
// Create the case. |
|
ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters); |
|
LoopRequirement requirement; |
|
|
|
if (loopType == LOOPTYPE_FOR && loopCountType == LOOPCOUNT_CONSTANT) |
|
{ |
|
if (loopCase == LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK || |
|
loopCase == LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST || |
|
loopCase == LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST || |
|
loopCase == LOOPCASE_SELECT_ITERATION_COUNT || |
|
loopCase == LOOPCASE_VECTOR_COUNTER || |
|
loopCase == LOOPCASE_SEQUENCE) |
|
requirement = LOOPREQUIREMENT_DYNAMIC; |
|
else |
|
requirement = LOOPREQUIREMENT_STANDARD; |
|
} |
|
else |
|
requirement = LOOPREQUIREMENT_DYNAMIC; |
|
|
|
return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, requirement, vertexShaderSource.c_str(), fragmentShaderSource.c_str()); |
|
}; |
|
|
|
// ShaderLoopTests. |
|
|
|
ShaderLoopTests::ShaderLoopTests(Context& context) |
|
: TestCaseGroup(context, "loops", "Loop Tests") |
|
{ |
|
} |
|
|
|
ShaderLoopTests::~ShaderLoopTests (void) |
|
{ |
|
} |
|
|
|
void ShaderLoopTests::init (void) |
|
{ |
|
// Loop cases. |
|
|
|
static const ShaderType s_shaderTypes[] = |
|
{ |
|
SHADERTYPE_VERTEX, |
|
SHADERTYPE_FRAGMENT |
|
}; |
|
|
|
static const DataType s_countDataType[] = |
|
{ |
|
TYPE_INT, |
|
TYPE_FLOAT |
|
}; |
|
|
|
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); |
|
|
|
string groupName = string(loopTypeName) + "_" + string(loopCountName) + "_iterations"; |
|
string groupDesc = string("Loop tests with ") + loopCountName + " loop counter."; |
|
TestCaseGroup* group = new TestCaseGroup(m_context, groupName.c_str(), groupDesc.c_str()); |
|
addChild(group); |
|
|
|
// Generic cases. |
|
|
|
for (int precision = 0; precision < PRECISION_LAST; precision++) |
|
{ |
|
const char* precisionName = getPrecisionName((Precision)precision); |
|
|
|
for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++) |
|
{ |
|
DataType loopDataType = s_countDataType[dataTypeNdx]; |
|
const char* dataTypeName = getDataTypeName(loopDataType); |
|
|
|
for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++) |
|
{ |
|
ShaderType shaderType = s_shaderTypes[shaderTypeNdx]; |
|
const char* shaderTypeName = getShaderTypeName(shaderType); |
|
bool isVertexCase = (shaderType == SHADERTYPE_VERTEX); |
|
|
|
string name = string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName; |
|
string desc = string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader."; |
|
group->addChild(createGenericLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (Precision)precision, loopDataType)); |
|
} |
|
} |
|
} |
|
|
|
// 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++) |
|
{ |
|
ShaderType shaderType = s_shaderTypes[shaderTypeNdx]; |
|
const char* shaderTypeName = getShaderTypeName(shaderType); |
|
bool isVertexCase = (shaderType == SHADERTYPE_VERTEX); |
|
|
|
string name = string(loopCaseName) + "_" + shaderTypeName; |
|
string desc = string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader."; |
|
group->addChild(createSpecialLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType)); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Additional smaller handwritten tests. |
|
const std::vector<tcu::TestNode*> children = gls::ShaderLibrary(m_context.getTestContext(), m_context.getRenderContext(), m_context.getContextInfo()).loadShaderFile("shaders/loops.test"); |
|
for (int i = 0; i < (int)children.size(); i++) |
|
addChild(children[i]); |
|
} |
|
|
|
} // Functional |
|
} // gles2 |
|
} // deqp
|
|
|