vktShaderRender.hpp
vktShaderRenderDiscardTests.cpp
vktShaderRenderDiscardTests.hpp
+ vktShaderRenderIndexingTests.cpp
+ vktShaderRenderIndexingTests.hpp
+ vktShaderRenderLoopTests.cpp
+ vktShaderRenderLoopTests.hpp
+ vktShaderRenderMatrixTests.cpp
+ vktShaderRenderMatrixTests.hpp
+ vktShaderRenderOperatorTests.cpp
+ vktShaderRenderOperatorTests.hpp
+ vktShaderRenderReturnTests.cpp
+ vktShaderRenderReturnTests.hpp
+ vktShaderRenderStructTests.cpp
+ vktShaderRenderStructTests.hpp
+ vktShaderRenderSwitchTests.cpp
+ vktShaderRenderSwitchTests.hpp
)
set(DEQP_VK_SHADERRENDER_LIBS
namespace sr
{
+class LineStream
+{
+public:
+ LineStream (int indent = 0) { m_indent = indent; }
+ ~LineStream (void) {}
+
+ const char* str (void) const { m_string = m_stream.str(); return m_string.c_str(); }
+ LineStream& operator<< (const char* line) { for (int i = 0; i < m_indent; i++) { m_stream << "\t"; } m_stream << line << "\n"; return *this; }
+
+private:
+ int m_indent;
+ std::ostringstream m_stream;
+ mutable std::string m_string;
+};
+
class QuadGrid;
class ShaderRenderCaseInstance;
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader indexing (arrays, vector, matrices) tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderIndexingTests.hpp"
+#include "vktShaderRender.hpp"
+#include "gluShaderUtil.hpp"
+#include "tcuStringTemplate.hpp"
+
+#include <map>
+
+using namespace std;
+using namespace tcu;
+using namespace glu;
+
+namespace vkt
+{
+namespace sr
+{
+
+namespace
+{
+
+enum IndexAccessType
+{
+ INDEXACCESS_STATIC = 0,
+ INDEXACCESS_DYNAMIC,
+ INDEXACCESS_STATIC_LOOP,
+ INDEXACCESS_DYNAMIC_LOOP,
+
+ INDEXACCESS_LAST
+};
+
+static const char* getIndexAccessTypeName (IndexAccessType accessType)
+{
+ static const char* s_names[INDEXACCESS_LAST] =
+ {
+ "static",
+ "dynamic",
+ "static_loop",
+ "dynamic_loop"
+ };
+
+ DE_ASSERT(deInBounds32((int)accessType, 0, INDEXACCESS_LAST));
+ return s_names[(int)accessType];
+}
+
+enum VectorAccessType
+{
+ DIRECT = 0,
+ COMPONENT,
+ SUBSCRIPT_STATIC,
+ SUBSCRIPT_DYNAMIC,
+ SUBSCRIPT_STATIC_LOOP,
+ SUBSCRIPT_DYNAMIC_LOOP,
+
+ VECTORACCESS_LAST
+};
+
+static const char* getVectorAccessTypeName (VectorAccessType accessType)
+{
+ static const char* s_names[VECTORACCESS_LAST] =
+ {
+ "direct",
+ "component",
+ "static_subscript",
+ "dynamic_subscript",
+ "static_loop_subscript",
+ "dynamic_loop_subscript"
+ };
+
+ DE_ASSERT(deInBounds32((int)accessType, 0, VECTORACCESS_LAST));
+ return s_names[(int)accessType];
+}
+
+void evalArrayCoordsFloat (ShaderEvalContext& c) { c.color.x() = 1.875f * c.coords.x(); }
+void evalArrayCoordsVec2 (ShaderEvalContext& c) { c.color.xy() = 1.875f * c.coords.swizzle(0,1); }
+void evalArrayCoordsVec3 (ShaderEvalContext& c) { c.color.xyz() = 1.875f * c.coords.swizzle(0,1,2); }
+void evalArrayCoordsVec4 (ShaderEvalContext& c) { c.color = 1.875f * c.coords; }
+
+static ShaderEvalFunc getArrayCoordsEvalFunc (DataType dataType)
+{
+ if (dataType == TYPE_FLOAT) return evalArrayCoordsFloat;
+ else if (dataType == TYPE_FLOAT_VEC2) return evalArrayCoordsVec2;
+ else if (dataType == TYPE_FLOAT_VEC3) return evalArrayCoordsVec3;
+ else if (dataType == TYPE_FLOAT_VEC4) return evalArrayCoordsVec4;
+
+ DE_FATAL("Invalid data type.");
+ return NULL;
+}
+
+void evalArrayUniformFloat (ShaderEvalContext& c) { c.color.x() = 1.875f * c.constCoords.x(); }
+void evalArrayUniformVec2 (ShaderEvalContext& c) { c.color.xy() = 1.875f * c.constCoords.swizzle(0,1); }
+void evalArrayUniformVec3 (ShaderEvalContext& c) { c.color.xyz() = 1.875f * c.constCoords.swizzle(0,1,2); }
+void evalArrayUniformVec4 (ShaderEvalContext& c) { c.color = 1.875f * c.constCoords; }
+
+static ShaderEvalFunc getArrayUniformEvalFunc (DataType dataType)
+{
+ if (dataType == TYPE_FLOAT) return evalArrayUniformFloat;
+ else if (dataType == TYPE_FLOAT_VEC2) return evalArrayUniformVec2;
+ else if (dataType == TYPE_FLOAT_VEC3) return evalArrayUniformVec3;
+ else if (dataType == TYPE_FLOAT_VEC4) return evalArrayUniformVec4;
+
+ DE_FATAL("Invalid data type.");
+ return NULL;
+}
+
+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 "";
+ }
+}
+
+class IndexingTestUniformSetup : public UniformSetup
+{
+public:
+ IndexingTestUniformSetup (const DataType varType, bool usesArray)
+ : m_varType(varType)
+ , m_usesArray(usesArray)
+ {}
+ virtual ~IndexingTestUniformSetup (void)
+ {}
+
+ virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
+
+private:
+ const DataType m_varType;
+ const bool m_usesArray;
+};
+
+void IndexingTestUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
+{
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UI_THREE);
+ instance.useUniform(4u, UI_FOUR);
+
+ if (m_usesArray)
+ {
+ Vec4 arr[4];
+ if (m_varType == TYPE_FLOAT)
+ {
+ arr[0] = Vec4(constCoords.x());
+ arr[1] = Vec4(constCoords.x() * 0.5f);
+ arr[2] = Vec4(constCoords.x() * 0.25f);
+ arr[3] = Vec4(constCoords.x() * 0.125f);
+ }
+ else if (m_varType == TYPE_FLOAT_VEC2)
+ {
+ arr[0] = constCoords.swizzle(0, 1).toWidth<4>();
+ arr[1] = (constCoords.swizzle(0, 1) * 0.5f).toWidth<4>();
+ arr[2] = (constCoords.swizzle(0, 1) * 0.25f).toWidth<4>();
+ arr[3] = (constCoords.swizzle(0, 1) * 0.125f).toWidth<4>();
+ }
+ else if (m_varType == TYPE_FLOAT_VEC3)
+ {
+ arr[0] = constCoords.swizzle(0, 1, 2).toWidth<4>();
+ arr[1] = (constCoords.swizzle(0, 1, 2) * 0.5f).toWidth<4>();
+ arr[2] = (constCoords.swizzle(0, 1, 2) * 0.25f).toWidth<4>();
+ arr[3] = (constCoords.swizzle(0, 1, 2) * 0.125f).toWidth<4>();
+ }
+ else if (m_varType == TYPE_FLOAT_VEC4)
+ {
+ arr[0] = constCoords;
+ arr[1] = constCoords * 0.5f;
+ arr[2] = constCoords * 0.25f;
+ arr[3] = constCoords * 0.125f;
+ }
+ else
+ throw tcu::TestError("invalid data type for u_arr");
+
+ instance.addUniform(5u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(Vec4) * 4, arr[0].getPtr());
+ }
+}
+
+// ShaderIndexingCase
+
+class ShaderIndexingCase : public ShaderRenderCase
+{
+public:
+ ShaderIndexingCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ bool isVertexCase,
+ const ShaderEvalFunc evalFunc,
+ const std::string& vertShaderSource,
+ const std::string& fragShaderSource,
+ const DataType varType,
+ const bool usesArray);
+ virtual ~ShaderIndexingCase (void);
+
+private:
+ ShaderIndexingCase (const ShaderIndexingCase&); // not allowed!
+ ShaderIndexingCase& operator= (const ShaderIndexingCase&); // not allowed!
+};
+
+ShaderIndexingCase::ShaderIndexingCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ const bool isVertexCase,
+ const ShaderEvalFunc evalFunc,
+ const std::string& vertShaderSource,
+ const std::string& fragShaderSource,
+ const DataType varType,
+ const bool usesArray)
+ : ShaderRenderCase(testCtx, name, description, isVertexCase, evalFunc, new IndexingTestUniformSetup(varType, usesArray), DE_NULL)
+{
+ m_vertShaderSource = vertShaderSource;
+ m_fragShaderSource = fragShaderSource;
+}
+
+ShaderIndexingCase::~ShaderIndexingCase (void)
+{
+}
+
+// Test case builders.
+
+static de::MovePtr<ShaderIndexingCase> createVaryingArrayCase (tcu::TestContext& context,
+ const std::string& caseName,
+ const std::string& description,
+ DataType varType,
+ IndexAccessType vertAccess,
+ IndexAccessType fragAccess)
+{
+ std::ostringstream vtx;
+ vtx << "#version 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+ vtx << "layout(location = 0) in highp vec4 a_position;\n";
+ vtx << "layout(location = 1) in highp vec4 a_coords;\n";
+ if (vertAccess == INDEXACCESS_DYNAMIC)
+ {
+ vtx << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ vtx << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ vtx << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ vtx << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+ else if (vertAccess == INDEXACCESS_DYNAMIC_LOOP)
+ vtx << "layout(std140, binding = 4) uniform something { mediump int ui_four; };\n";
+ vtx << "layout(location = 0) out ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+ if (vertAccess == INDEXACCESS_STATIC)
+ {
+ vtx << " var[0] = ${VAR_TYPE}(a_coords);\n";
+ vtx << " var[1] = ${VAR_TYPE}(a_coords) * 0.5;\n";
+ vtx << " var[2] = ${VAR_TYPE}(a_coords) * 0.25;\n";
+ vtx << " var[3] = ${VAR_TYPE}(a_coords) * 0.125;\n";
+ }
+ else if (vertAccess == INDEXACCESS_DYNAMIC)
+ {
+ vtx << " var[ui_zero] = ${VAR_TYPE}(a_coords);\n";
+ vtx << " var[ui_one] = ${VAR_TYPE}(a_coords) * 0.5;\n";
+ vtx << " var[ui_two] = ${VAR_TYPE}(a_coords) * 0.25;\n";
+ vtx << " var[ui_three] = ${VAR_TYPE}(a_coords) * 0.125;\n";
+ }
+ else if (vertAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ vtx << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
+ vtx << " for (int i = 0; i < 4; i++)\n";
+ vtx << " {\n";
+ vtx << " var[i] = ${VAR_TYPE}(coords);\n";
+ vtx << " coords = coords * 0.5;\n";
+ vtx << " }\n";
+ }
+ else
+ {
+ DE_ASSERT(vertAccess == INDEXACCESS_DYNAMIC_LOOP);
+ vtx << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
+ vtx << " for (int i = 0; i < ui_four; i++)\n";
+ vtx << " {\n";
+ vtx << " var[i] = ${VAR_TYPE}(coords);\n";
+ vtx << " coords = coords * 0.5;\n";
+ vtx << " }\n";
+ }
+ vtx << "}\n";
+
+ std::ostringstream frag;
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\n";
+ frag << "precision mediump int;\n";
+ frag << "layout(location = 0) out mediump vec4 o_color;\n";
+ if (fragAccess == INDEXACCESS_DYNAMIC)
+ {
+ frag << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ frag << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ frag << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ frag << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+ else if (fragAccess == INDEXACCESS_DYNAMIC_LOOP)
+ frag << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
+ frag << "layout(location = 0) in ${PRECISION} ${VAR_TYPE} var[${ARRAY_LEN}];\n";
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+ frag << " ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
+ if (fragAccess == INDEXACCESS_STATIC)
+ {
+ frag << " res += var[0];\n";
+ frag << " res += var[1];\n";
+ frag << " res += var[2];\n";
+ frag << " res += var[3];\n";
+ }
+ else if (fragAccess == INDEXACCESS_DYNAMIC)
+ {
+ frag << " res += var[ui_zero];\n";
+ frag << " res += var[ui_one];\n";
+ frag << " res += var[ui_two];\n";
+ frag << " res += var[ui_three];\n";
+ }
+ else if (fragAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ frag << " for (int i = 0; i < 4; i++)\n";
+ frag << " res += var[i];\n";
+ }
+ else
+ {
+ DE_ASSERT(fragAccess == INDEXACCESS_DYNAMIC_LOOP);
+ frag << " for (int i = 0; i < ui_four; i++)\n";
+ frag << " res += var[i];\n";
+ }
+ frag << " o_color = vec4(res${PADDING});\n";
+ frag << "}\n";
+
+ // Fill in shader templates.
+ map<string, string> params;
+ params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
+ params.insert(pair<string, string>("ARRAY_LEN", "4"));
+ params.insert(pair<string, string>("PRECISION", "mediump"));
+
+ if (varType == TYPE_FLOAT)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC2)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC3)
+ params.insert(pair<string, string>("PADDING", ", 1.0"));
+ else
+ params.insert(pair<string, string>("PADDING", ""));
+
+ StringTemplate vertTemplate(vtx.str());
+ StringTemplate fragTemplate(frag.str());
+ string vertexShaderSource = vertTemplate.specialize(params);
+ string fragmentShaderSource = fragTemplate.specialize(params);
+
+ ShaderEvalFunc evalFunc = getArrayCoordsEvalFunc(varType);
+ return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, description, true, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
+}
+
+static de::MovePtr<ShaderIndexingCase> createUniformArrayCase (tcu::TestContext& context,
+ const std::string& caseName,
+ const std::string& description,
+ bool isVertexCase,
+ DataType varType,
+ IndexAccessType readAccess)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = isVertexCase ? vtx : frag;
+
+ vtx << "#version 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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 (isVertexCase)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 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 (readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+ else if (readAccess == INDEXACCESS_DYNAMIC_LOOP)
+ op << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
+
+ op << "layout(std140, binding = 5) uniform something5 { ${PRECISION} ${VAR_TYPE} u_arr[${ARRAY_LEN}]; };\n";
+
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+
+ // Read array.
+ op << " ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
+ if (readAccess == INDEXACCESS_STATIC)
+ {
+ op << " res += u_arr[0];\n";
+ op << " res += u_arr[1];\n";
+ op << " res += u_arr[2];\n";
+ op << " res += u_arr[3];\n";
+ }
+ else if (readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << " res += u_arr[ui_zero];\n";
+ op << " res += u_arr[ui_one];\n";
+ op << " res += u_arr[ui_two];\n";
+ op << " res += u_arr[ui_three];\n";
+ }
+ else if (readAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < 4; i++)\n";
+ op << " res += u_arr[i];\n";
+ }
+ else
+ {
+ DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < ui_four; i++)\n";
+ op << " res += u_arr[i];\n";
+ }
+
+ if (isVertexCase)
+ {
+ vtx << " v_color = vec4(res${PADDING});\n";
+ frag << " o_color = v_color;\n";
+ }
+ else
+ {
+ vtx << " v_coords = a_coords;\n";
+ frag << " o_color = vec4(res${PADDING});\n";
+ }
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ // Fill in shader templates.
+ map<string, string> params;
+ params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
+ params.insert(pair<string, string>("ARRAY_LEN", "4"));
+ params.insert(pair<string, string>("PRECISION", "mediump"));
+
+ if (varType == TYPE_FLOAT)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC2)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC3)
+ params.insert(pair<string, string>("PADDING", ", 1.0"));
+ else
+ params.insert(pair<string, string>("PADDING", ""));
+
+ StringTemplate vertTemplate(vtx.str());
+ StringTemplate fragTemplate(frag.str());
+ string vertexShaderSource = vertTemplate.specialize(params);
+ string fragmentShaderSource = fragTemplate.specialize(params);
+
+ ShaderEvalFunc evalFunc = getArrayUniformEvalFunc(varType);
+ return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, true));
+}
+
+static de::MovePtr<ShaderIndexingCase> createTmpArrayCase (tcu::TestContext& context,
+ const std::string& caseName,
+ const std::string& description,
+ bool isVertexCase,
+ DataType varType,
+ IndexAccessType writeAccess,
+ IndexAccessType readAccess)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = isVertexCase ? vtx : frag;
+
+ vtx << "#version 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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 (isVertexCase)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 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 (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+
+ if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
+ op << "layout(std140, binding = 4) uniform something4 { mediump int ui_four; };\n";
+
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+
+ // Write array.
+ if (isVertexCase)
+ op << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
+ else
+ op << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
+
+ op << " ${PRECISION} ${VAR_TYPE} arr[${ARRAY_LEN}];\n";
+ if (writeAccess == INDEXACCESS_STATIC)
+ {
+ op << " arr[0] = ${VAR_TYPE}(coords);\n";
+ op << " arr[1] = ${VAR_TYPE}(coords) * 0.5;\n";
+ op << " arr[2] = ${VAR_TYPE}(coords) * 0.25;\n";
+ op << " arr[3] = ${VAR_TYPE}(coords) * 0.125;\n";
+ }
+ else if (writeAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << " arr[ui_zero] = ${VAR_TYPE}(coords);\n";
+ op << " arr[ui_one] = ${VAR_TYPE}(coords) * 0.5;\n";
+ op << " arr[ui_two] = ${VAR_TYPE}(coords) * 0.25;\n";
+ op << " arr[ui_three] = ${VAR_TYPE}(coords) * 0.125;\n";
+ }
+ else if (writeAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < 4; i++)\n";
+ op << " {\n";
+ op << " arr[i] = ${VAR_TYPE}(coords);\n";
+ op << " coords = coords * 0.5;\n";
+ op << " }\n";
+ }
+ else
+ {
+ DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < ui_four; i++)\n";
+ op << " {\n";
+ op << " arr[i] = ${VAR_TYPE}(coords);\n";
+ op << " coords = coords * 0.5;\n";
+ op << " }\n";
+ }
+
+ // Read array.
+ op << " ${PRECISION} ${VAR_TYPE} res = ${VAR_TYPE}(0.0);\n";
+ if (readAccess == INDEXACCESS_STATIC)
+ {
+ op << " res += arr[0];\n";
+ op << " res += arr[1];\n";
+ op << " res += arr[2];\n";
+ op << " res += arr[3];\n";
+ }
+ else if (readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << " res += arr[ui_zero];\n";
+ op << " res += arr[ui_one];\n";
+ op << " res += arr[ui_two];\n";
+ op << " res += arr[ui_three];\n";
+ }
+ else if (readAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < 4; i++)\n";
+ op << " res += arr[i];\n";
+ }
+ else
+ {
+ DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < ui_four; i++)\n";
+ op << " res += arr[i];\n";
+ }
+
+ if (isVertexCase)
+ {
+ vtx << " v_color = vec4(res${PADDING});\n";
+ frag << " o_color = v_color;\n";
+ }
+ else
+ {
+ vtx << " v_coords = a_coords;\n";
+ frag << " o_color = vec4(res${PADDING});\n";
+ }
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ // Fill in shader templates.
+ map<string, string> params;
+ params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
+ params.insert(pair<string, string>("ARRAY_LEN", "4"));
+ params.insert(pair<string, string>("PRECISION", "mediump"));
+
+ if (varType == TYPE_FLOAT)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC2)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
+ else if (varType == TYPE_FLOAT_VEC3)
+ params.insert(pair<string, string>("PADDING", ", 1.0"));
+ else
+ params.insert(pair<string, string>("PADDING", ""));
+
+ StringTemplate vertTemplate(vtx.str());
+ StringTemplate fragTemplate(frag.str());
+ string vertexShaderSource = vertTemplate.specialize(params);
+ string fragmentShaderSource = fragTemplate.specialize(params);
+
+ ShaderEvalFunc evalFunc = getArrayCoordsEvalFunc(varType);
+ return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
+}
+
+// VECTOR SUBSCRIPT.
+
+void evalSubscriptVec2 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y()); }
+void evalSubscriptVec3 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z()); }
+void evalSubscriptVec4 (ShaderEvalContext& c) { c.color.xyz() = Vec3(c.coords.x() + 0.5f*c.coords.y() + 0.25f*c.coords.z() + 0.125f*c.coords.w()); }
+
+static ShaderEvalFunc getVectorSubscriptEvalFunc (DataType dataType)
+{
+ if (dataType == TYPE_FLOAT_VEC2) return evalSubscriptVec2;
+ else if (dataType == TYPE_FLOAT_VEC3) return evalSubscriptVec3;
+ else if (dataType == TYPE_FLOAT_VEC4) return evalSubscriptVec4;
+
+ DE_FATAL("Invalid data type.");
+ return NULL;
+}
+
+static de::MovePtr<ShaderIndexingCase> createVectorSubscriptCase (tcu::TestContext& context,
+ const std::string& caseName,
+ const std::string& description,
+ bool isVertexCase,
+ DataType varType,
+ VectorAccessType writeAccess,
+ VectorAccessType readAccess)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = isVertexCase ? vtx : frag;
+
+ int vecLen = getDataTypeScalarSize(varType);
+ const char* vecLenName = getIntUniformName(vecLen);
+
+ vtx << "#version 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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 (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 (writeAccess == SUBSCRIPT_DYNAMIC || readAccess == SUBSCRIPT_DYNAMIC)
+ {
+ op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ if (vecLen >= 2) op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ if (vecLen >= 3) op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ if (vecLen >= 4) op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+
+ if (writeAccess == SUBSCRIPT_DYNAMIC_LOOP || readAccess == SUBSCRIPT_DYNAMIC_LOOP)
+ op << "layout(std140, binding = " << vecLen << ") uniform something" << vecLen << " { mediump int " << vecLenName << "; };\n";
+
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+
+ // Write vector.
+ if (isVertexCase)
+ op << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(a_coords);\n";
+ else
+ op << " ${PRECISION} ${VAR_TYPE} coords = ${VAR_TYPE}(v_coords);\n";
+
+ op << " ${PRECISION} ${VAR_TYPE} tmp;\n";
+ if (writeAccess == DIRECT)
+ op << " tmp = coords.${SWIZZLE} * vec4(1.0, 0.5, 0.25, 0.125).${SWIZZLE};\n";
+ else if (writeAccess == COMPONENT)
+ {
+ op << " tmp.x = coords.x;\n";
+ if (vecLen >= 2) op << " tmp.y = coords.y * 0.5;\n";
+ if (vecLen >= 3) op << " tmp.z = coords.z * 0.25;\n";
+ if (vecLen >= 4) op << " tmp.w = coords.w * 0.125;\n";
+ }
+ else if (writeAccess == SUBSCRIPT_STATIC)
+ {
+ op << " tmp[0] = coords.x;\n";
+ if (vecLen >= 2) op << " tmp[1] = coords.y * 0.5;\n";
+ if (vecLen >= 3) op << " tmp[2] = coords.z * 0.25;\n";
+ if (vecLen >= 4) op << " tmp[3] = coords.w * 0.125;\n";
+ }
+ else if (writeAccess == SUBSCRIPT_DYNAMIC)
+ {
+ op << " tmp[ui_zero] = coords.x;\n";
+ if (vecLen >= 2) op << " tmp[ui_one] = coords.y * 0.5;\n";
+ if (vecLen >= 3) op << " tmp[ui_two] = coords.z * 0.25;\n";
+ if (vecLen >= 4) op << " tmp[ui_three] = coords.w * 0.125;\n";
+ }
+ else if (writeAccess == SUBSCRIPT_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < " << vecLen << "; i++)\n";
+ op << " {\n";
+ op << " tmp[i] = coords.x;\n";
+ op << " coords = coords.${ROT_SWIZZLE} * 0.5;\n";
+ op << " }\n";
+ }
+ else
+ {
+ DE_ASSERT(writeAccess == SUBSCRIPT_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < " << vecLenName << "; i++)\n";
+ op << " {\n";
+ op << " tmp[i] = coords.x;\n";
+ op << " coords = coords.${ROT_SWIZZLE} * 0.5;\n";
+ op << " }\n";
+ }
+
+ // Read vector.
+ op << " ${PRECISION} float res = 0.0;\n";
+ if (readAccess == DIRECT)
+ op << " res = dot(tmp, ${VAR_TYPE}(1.0));\n";
+ else if (readAccess == COMPONENT)
+ {
+ op << " res += tmp.x;\n";
+ if (vecLen >= 2) op << " res += tmp.y;\n";
+ if (vecLen >= 3) op << " res += tmp.z;\n";
+ if (vecLen >= 4) op << " res += tmp.w;\n";
+ }
+ else if (readAccess == SUBSCRIPT_STATIC)
+ {
+ op << " res += tmp[0];\n";
+ if (vecLen >= 2) op << " res += tmp[1];\n";
+ if (vecLen >= 3) op << " res += tmp[2];\n";
+ if (vecLen >= 4) op << " res += tmp[3];\n";
+ }
+ else if (readAccess == SUBSCRIPT_DYNAMIC)
+ {
+ op << " res += tmp[ui_zero];\n";
+ if (vecLen >= 2) op << " res += tmp[ui_one];\n";
+ if (vecLen >= 3) op << " res += tmp[ui_two];\n";
+ if (vecLen >= 4) op << " res += tmp[ui_three];\n";
+ }
+ else if (readAccess == SUBSCRIPT_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < " << vecLen << "; i++)\n";
+ op << " res += tmp[i];\n";
+ }
+ else
+ {
+ DE_ASSERT(readAccess == SUBSCRIPT_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < " << vecLenName << "; i++)\n";
+ op << " res += tmp[i];\n";
+ }
+
+ if (isVertexCase)
+ {
+ vtx << " v_color = vec3(res);\n";
+ frag << " o_color = vec4(v_color.rgb, 1.0);\n";
+ }
+ else
+ {
+ vtx << " v_coords = a_coords;\n";
+ frag << " o_color = vec4(vec3(res), 1.0);\n";
+ }
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ // Fill in shader templates.
+ static const char* s_swizzles[5] = { "", "x", "xy", "xyz", "xyzw" };
+ static const char* s_rotSwizzles[5] = { "", "x", "yx", "yzx", "yzwx" };
+
+ map<string, string> params;
+ params.insert(pair<string, string>("VAR_TYPE", getDataTypeName(varType)));
+ params.insert(pair<string, string>("PRECISION", "mediump"));
+ params.insert(pair<string, string>("SWIZZLE", s_swizzles[vecLen]));
+ params.insert(pair<string, string>("ROT_SWIZZLE", s_rotSwizzles[vecLen]));
+
+ StringTemplate vertTemplate(vtx.str());
+ StringTemplate fragTemplate(frag.str());
+ string vertexShaderSource = vertTemplate.specialize(params);
+ string fragmentShaderSource = fragTemplate.specialize(params);
+
+ ShaderEvalFunc evalFunc = getVectorSubscriptEvalFunc(varType);
+ return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
+}
+
+// MATRIX SUBSCRIPT.
+
+void evalSubscriptMat2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2); }
+void evalSubscriptMat2x3 (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2) + 0.5f*c.coords.swizzle(1,2,3); }
+void evalSubscriptMat2x4 (ShaderEvalContext& c) { c.color = c.coords.swizzle(0,1,2,3) + 0.5f*c.coords.swizzle(1,2,3,0); }
+
+void evalSubscriptMat3x2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2) + 0.25f*c.coords.swizzle(2,3); }
+void evalSubscriptMat3 (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2) + 0.5f*c.coords.swizzle(1,2,3) + 0.25f*c.coords.swizzle(2,3,0); }
+void evalSubscriptMat3x4 (ShaderEvalContext& c) { c.color = c.coords.swizzle(0,1,2,3) + 0.5f*c.coords.swizzle(1,2,3,0) + 0.25f*c.coords.swizzle(2,3,0,1); }
+
+void evalSubscriptMat4x2 (ShaderEvalContext& c) { c.color.xy() = c.coords.swizzle(0,1) + 0.5f*c.coords.swizzle(1,2) + 0.25f*c.coords.swizzle(2,3) + 0.125f*c.coords.swizzle(3,0); }
+void evalSubscriptMat4x3 (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2) + 0.5f*c.coords.swizzle(1,2,3) + 0.25f*c.coords.swizzle(2,3,0) + 0.125f*c.coords.swizzle(3,0,1); }
+void evalSubscriptMat4 (ShaderEvalContext& c) { c.color = c.coords + 0.5f*c.coords.swizzle(1,2,3,0) + 0.25f*c.coords.swizzle(2,3,0,1) + 0.125f*c.coords.swizzle(3,0,1,2); }
+
+static ShaderEvalFunc getMatrixSubscriptEvalFunc (DataType dataType)
+{
+ switch (dataType)
+ {
+ case TYPE_FLOAT_MAT2: return evalSubscriptMat2;
+ case TYPE_FLOAT_MAT2X3: return evalSubscriptMat2x3;
+ case TYPE_FLOAT_MAT2X4: return evalSubscriptMat2x4;
+ case TYPE_FLOAT_MAT3X2: return evalSubscriptMat3x2;
+ case TYPE_FLOAT_MAT3: return evalSubscriptMat3;
+ case TYPE_FLOAT_MAT3X4: return evalSubscriptMat3x4;
+ case TYPE_FLOAT_MAT4X2: return evalSubscriptMat4x2;
+ case TYPE_FLOAT_MAT4X3: return evalSubscriptMat4x3;
+ case TYPE_FLOAT_MAT4: return evalSubscriptMat4;
+
+ default:
+ DE_FATAL("Invalid data type.");
+ return DE_NULL;
+ }
+}
+
+static de::MovePtr<ShaderIndexingCase> createMatrixSubscriptCase (tcu::TestContext& context,
+ const std::string& caseName,
+ const std::string& description,
+ bool isVertexCase,
+ DataType varType,
+ IndexAccessType writeAccess,
+ IndexAccessType readAccess)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = isVertexCase ? vtx : frag;
+
+ int numCols = getDataTypeMatrixNumColumns(varType);
+ int numRows = getDataTypeMatrixNumRows(varType);
+ const char* matSizeName = getIntUniformName(numCols);
+ DataType vecType = getDataTypeFloatVec(numRows);
+
+ vtx << "#version 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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 (isVertexCase)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 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 (writeAccess == INDEXACCESS_DYNAMIC || readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << "layout(std140, binding = 0) uniform something0 { mediump int ui_zero; };\n";
+ if (numCols >= 2) op << "layout(std140, binding = 1) uniform something1 { mediump int ui_one; };\n";
+ if (numCols >= 3) op << "layout(std140, binding = 2) uniform something2 { mediump int ui_two; };\n";
+ if (numCols >= 4) op << "layout(std140, binding = 3) uniform something3 { mediump int ui_three; };\n";
+ }
+
+ if (writeAccess == INDEXACCESS_DYNAMIC_LOOP || readAccess == INDEXACCESS_DYNAMIC_LOOP)
+ op << "layout(std140, binding = " << numCols << ") uniform something" << numCols << " { mediump int " << matSizeName << "; };\n";
+
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+
+ // Write matrix.
+ if (isVertexCase)
+ op << " ${PRECISION} vec4 coords = a_coords;\n";
+ else
+ op << " ${PRECISION} vec4 coords = v_coords;\n";
+
+ op << " ${PRECISION} ${MAT_TYPE} tmp;\n";
+ if (writeAccess == INDEXACCESS_STATIC)
+ {
+ op << " tmp[0] = ${VEC_TYPE}(coords);\n";
+ if (numCols >= 2) op << " tmp[1] = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
+ if (numCols >= 3) op << " tmp[2] = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
+ if (numCols >= 4) op << " tmp[3] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
+ }
+ else if (writeAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << " tmp[ui_zero] = ${VEC_TYPE}(coords);\n";
+ if (numCols >= 2) op << " tmp[ui_one] = ${VEC_TYPE}(coords.yzwx) * 0.5;\n";
+ if (numCols >= 3) op << " tmp[ui_two] = ${VEC_TYPE}(coords.zwxy) * 0.25;\n";
+ if (numCols >= 4) op << " tmp[ui_three] = ${VEC_TYPE}(coords.wxyz) * 0.125;\n";
+ }
+ else if (writeAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < " << numCols << "; i++)\n";
+ op << " {\n";
+ op << " tmp[i] = ${VEC_TYPE}(coords);\n";
+ op << " coords = coords.yzwx * 0.5;\n";
+ op << " }\n";
+ }
+ else
+ {
+ DE_ASSERT(writeAccess == INDEXACCESS_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < " << matSizeName << "; i++)\n";
+ op << " {\n";
+ op << " tmp[i] = ${VEC_TYPE}(coords);\n";
+ op << " coords = coords.yzwx * 0.5;\n";
+ op << " }\n";
+ }
+
+ // Read matrix.
+ op << " ${PRECISION} ${VEC_TYPE} res = ${VEC_TYPE}(0.0);\n";
+ if (readAccess == INDEXACCESS_STATIC)
+ {
+ op << " res += tmp[0];\n";
+ if (numCols >= 2) op << " res += tmp[1];\n";
+ if (numCols >= 3) op << " res += tmp[2];\n";
+ if (numCols >= 4) op << " res += tmp[3];\n";
+ }
+ else if (readAccess == INDEXACCESS_DYNAMIC)
+ {
+ op << " res += tmp[ui_zero];\n";
+ if (numCols >= 2) op << " res += tmp[ui_one];\n";
+ if (numCols >= 3) op << " res += tmp[ui_two];\n";
+ if (numCols >= 4) op << " res += tmp[ui_three];\n";
+ }
+ else if (readAccess == INDEXACCESS_STATIC_LOOP)
+ {
+ op << " for (int i = 0; i < " << numCols << "; i++)\n";
+ op << " res += tmp[i];\n";
+ }
+ else
+ {
+ DE_ASSERT(readAccess == INDEXACCESS_DYNAMIC_LOOP);
+ op << " for (int i = 0; i < " << matSizeName << "; i++)\n";
+ op << " res += tmp[i];\n";
+ }
+
+ if (isVertexCase)
+ {
+ vtx << " v_color = vec4(res${PADDING});\n";
+ frag << " o_color = v_color;\n";
+ }
+ else
+ {
+ vtx << " v_coords = a_coords;\n";
+ frag << " o_color = vec4(res${PADDING});\n";
+ }
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ // Fill in shader templates.
+ map<string, string> params;
+ params.insert(pair<string, string>("MAT_TYPE", getDataTypeName(varType)));
+ params.insert(pair<string, string>("VEC_TYPE", getDataTypeName(vecType)));
+ params.insert(pair<string, string>("PRECISION", "mediump"));
+
+ if (numRows == 2)
+ params.insert(pair<string, string>("PADDING", ", 0.0, 1.0"));
+ else if (numRows == 3)
+ params.insert(pair<string, string>("PADDING", ", 1.0"));
+ else
+ params.insert(pair<string, string>("PADDING", ""));
+
+ StringTemplate vertTemplate(vtx.str());
+ StringTemplate fragTemplate(frag.str());
+ string vertexShaderSource = vertTemplate.specialize(params);
+ string fragmentShaderSource = fragTemplate.specialize(params);
+
+ ShaderEvalFunc evalFunc = getMatrixSubscriptEvalFunc(varType);
+ return de::MovePtr<ShaderIndexingCase>(new ShaderIndexingCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource, fragmentShaderSource, varType, false));
+}
+
+// ShaderIndexingTests.
+
+class ShaderIndexingTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderIndexingTests (tcu::TestContext& context);
+ virtual ~ShaderIndexingTests (void);
+
+ virtual void init (void);
+
+private:
+ ShaderIndexingTests (const ShaderIndexingTests&); // not allowed!
+ ShaderIndexingTests& operator= (const ShaderIndexingTests&); // not allowed!
+};
+
+ShaderIndexingTests::ShaderIndexingTests(tcu::TestContext& context)
+ : TestCaseGroup(context, "indexing", "Indexing Tests")
+{
+}
+
+ShaderIndexingTests::~ShaderIndexingTests (void)
+{
+}
+
+void ShaderIndexingTests::init (void)
+{
+ static const ShaderType s_shaderTypes[] =
+ {
+ SHADERTYPE_VERTEX,
+ SHADERTYPE_FRAGMENT
+ };
+
+ static const DataType s_floatAndVecTypes[] =
+ {
+ TYPE_FLOAT,
+ TYPE_FLOAT_VEC2,
+ TYPE_FLOAT_VEC3,
+ TYPE_FLOAT_VEC4
+ };
+
+ // Varying array access cases.
+ {
+ de::MovePtr<TestCaseGroup> varyingGroup(new TestCaseGroup(m_testCtx, "varying_array", "Varying array access tests."));
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
+ {
+ DataType varType = s_floatAndVecTypes[typeNdx];
+ for (int vertAccess = 0; vertAccess < INDEXACCESS_LAST; vertAccess++)
+ {
+ for (int fragAccess = 0; fragAccess < INDEXACCESS_LAST; fragAccess++)
+ {
+ const char* vertAccessName = getIndexAccessTypeName((IndexAccessType)vertAccess);
+ const char* fragAccessName = getIndexAccessTypeName((IndexAccessType)fragAccess);
+ string name = string(getDataTypeName(varType)) + "_" + vertAccessName + "_write_" + fragAccessName + "_read";
+ string desc = string("Varying array with ") + vertAccessName + " write in vertex shader and " + fragAccessName + " read in fragment shader.";
+ de::MovePtr<ShaderIndexingCase> testCase(createVaryingArrayCase(m_testCtx, name, desc, varType, (IndexAccessType)vertAccess, (IndexAccessType)fragAccess));
+ varyingGroup->addChild(testCase.release());
+ }
+ }
+ }
+
+ addChild(varyingGroup.release());
+ }
+
+ // Uniform array access cases.
+ {
+ de::MovePtr<TestCaseGroup> uniformGroup(new TestCaseGroup(m_testCtx, "uniform_array", "Uniform array access tests."));
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
+ {
+ DataType varType = s_floatAndVecTypes[typeNdx];
+ for (int readAccess = 0; readAccess < INDEXACCESS_LAST; readAccess++)
+ {
+ const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ string name = string(getDataTypeName(varType)) + "_" + readAccessName + "_read_" + shaderTypeName;
+ string desc = string("Uniform array with ") + readAccessName + " read in " + shaderTypeName + " shader.";
+ bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
+ de::MovePtr<ShaderIndexingCase> testCase(createUniformArrayCase(m_testCtx, name, desc, isVertexCase, varType, (IndexAccessType)readAccess));
+ uniformGroup->addChild(testCase.release());
+ }
+ }
+ }
+
+ addChild(uniformGroup.release());
+ }
+
+ // Temporary array access cases.
+ {
+ de::MovePtr<TestCaseGroup> tmpGroup(new TestCaseGroup(m_testCtx, "tmp_array", "Temporary array access tests."));
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_floatAndVecTypes); typeNdx++)
+ {
+ DataType varType = s_floatAndVecTypes[typeNdx];
+ for (int writeAccess = 0; writeAccess < INDEXACCESS_LAST; writeAccess++)
+ {
+ for (int readAccess = 0; readAccess < INDEXACCESS_LAST; readAccess++)
+ {
+ const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
+ const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
+ string desc = string("Temporary array with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
+ bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
+ de::MovePtr<ShaderIndexingCase> testCase(createTmpArrayCase(m_testCtx, name, desc, isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
+ tmpGroup->addChild(testCase.release());
+ }
+ }
+ }
+ }
+
+ addChild(tmpGroup.release());
+ }
+
+ // Vector indexing with subscripts.
+ {
+ de::MovePtr<TestCaseGroup> vecGroup(new TestCaseGroup(m_testCtx, "vector_subscript", "Vector subscript indexing."));
+
+ static const DataType s_vectorTypes[] =
+ {
+ TYPE_FLOAT_VEC2,
+ TYPE_FLOAT_VEC3,
+ TYPE_FLOAT_VEC4
+ };
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_vectorTypes); typeNdx++)
+ {
+ DataType varType = s_vectorTypes[typeNdx];
+ for (int writeAccess = 0; writeAccess < VECTORACCESS_LAST; writeAccess++)
+ {
+ for (int readAccess = 0; readAccess < VECTORACCESS_LAST; readAccess++)
+ {
+ const char* writeAccessName = getVectorAccessTypeName((VectorAccessType)writeAccess);
+ const char* readAccessName = getVectorAccessTypeName((VectorAccessType)readAccess);
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
+ string desc = string("Vector subscript access with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
+ bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
+ de::MovePtr<ShaderIndexingCase> testCase(createVectorSubscriptCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, varType, (VectorAccessType)writeAccess, (VectorAccessType)readAccess));
+ vecGroup->addChild(testCase.release());
+ }
+ }
+ }
+ }
+
+ addChild(vecGroup.release());
+ }
+
+ // Matrix indexing with subscripts.
+ {
+ de::MovePtr<TestCaseGroup> matGroup(new TestCaseGroup(m_testCtx, "matrix_subscript", "Matrix subscript indexing."));
+
+ static const DataType s_matrixTypes[] =
+ {
+ TYPE_FLOAT_MAT2,
+ TYPE_FLOAT_MAT2X3,
+ TYPE_FLOAT_MAT2X4,
+ TYPE_FLOAT_MAT3X2,
+ TYPE_FLOAT_MAT3,
+ TYPE_FLOAT_MAT3X4,
+ TYPE_FLOAT_MAT4X2,
+ TYPE_FLOAT_MAT4X3,
+ TYPE_FLOAT_MAT4
+ };
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_matrixTypes); typeNdx++)
+ {
+ DataType varType = s_matrixTypes[typeNdx];
+ for (int writeAccess = 0; writeAccess < INDEXACCESS_LAST; writeAccess++)
+ {
+ for (int readAccess = 0; readAccess < INDEXACCESS_LAST; readAccess++)
+ {
+ const char* writeAccessName = getIndexAccessTypeName((IndexAccessType)writeAccess);
+ const char* readAccessName = getIndexAccessTypeName((IndexAccessType)readAccess);
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ string name = string(getDataTypeName(varType)) + "_" + writeAccessName + "_write_" + readAccessName + "_read_" + shaderTypeName;
+ string desc = string("Vector subscript access with ") + writeAccessName + " write and " + readAccessName + " read in " + shaderTypeName + " shader.";
+ bool isVertexCase = ((ShaderType)shaderType == SHADERTYPE_VERTEX);
+ de::MovePtr<ShaderIndexingCase> testCase(createMatrixSubscriptCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, varType, (IndexAccessType)writeAccess, (IndexAccessType)readAccess));
+ matGroup->addChild(testCase.release());
+ }
+ }
+ }
+ }
+
+ addChild(matGroup.release());
+ }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createIndexingTests (tcu::TestContext& testCtx)
+{
+ return new ShaderIndexingTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDERINDEXINGTESTS_HPP
+#define _VKTSHADERRENDERINDEXINGTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader indexing (arrays, vector, matrices) tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createIndexingTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERINDEXINGTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \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_TWO;
+ case 3: return UF_THREE;
+ case 4: return UF_FOUR;
+ case 5: return UF_FIVE;
+ case 6: return UF_SIX;
+ case 7: return UF_SEVEN;
+ case 8: return UF_EIGHT;
+ 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_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"
+ //"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 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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;\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 << " 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 140\n";
+ vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
+ vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
+
+ frag << "#version 140\n";
+ frag << "#extension GL_ARB_separate_shader_objects : enable\n";
+ frag << "#extension GL_ARB_shading_language_420pack : enable\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; }\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;
+
+ 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; }\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;
+
+ 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; } 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;
+
+ 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.
+ 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;
+
+ 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>("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 = 0; 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
--- /dev/null
+#ifndef _VKTSHADERRENDERLOOPTESTS_HPP
+#define _VKTSHADERRENDERLOOPTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader loop tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERLOOPTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader matrix arithmetic tests.
+ *
+ * Variables:
+ * + operation
+ * - mat OP mat
+ * - mat OP vec
+ * - vec OP mat
+ * - mat OP scalar
+ * - OP ( mat )
+ * - vec OP vec
+ * - OP mat
+ * + matrix source
+ * - constant (ctor)
+ * - uniform
+ * - vertex input
+ * - fragment input
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderMatrixTests.hpp"
+
+#include "vktShaderRender.hpp"
+#include "tcuVector.hpp"
+#include "tcuMatrix.hpp"
+#include "tcuMatrixUtil.hpp"
+#include "deStringUtil.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+using std::string;
+using std::vector;
+using namespace glu;
+
+using tcu::Vec2;
+using tcu::Vec3;
+using tcu::Vec4;
+using tcu::Mat2;
+using tcu::Mat2x3;
+using tcu::Mat2x4;
+using tcu::Mat3x2;
+using tcu::Mat3;
+using tcu::Mat3x4;
+using tcu::Mat4x2;
+using tcu::Mat4x3;
+using tcu::Mat4;
+
+// Uniform / constant values for tests.
+// \note Input1 should not contain 0 components as it is used as divisor in div cases.
+static const float s_constInFloat[2] = { 0.5f, -0.2f };
+static const Vec2 s_constInVec2[2] = { Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f) };
+static const Vec3 s_constInVec3[2] = { Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f) };
+static const Vec4 s_constInVec4[2] = { Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f) };
+
+static const float s_constInMat2x2[2][4] =
+{
+ {
+ -0.1f, 1.0f,
+ -0.2f, 0.0f,
+ },
+ {
+ 0.8f, 0.1f,
+ 0.5f, -0.9f,
+ },
+};
+static const float s_constInMat3x2[2][6] =
+{
+ {
+ 0.8f, -0.3f, 0.3f,
+ 1.0f, 1.2f, -1.2f,
+ },
+ {
+ 1.2f, -1.0f, 0.5f,
+ -0.8f, 1.1f, 0.3f,
+ },
+};
+static const float s_constInMat4x2[2][8] =
+{
+ {
+ -0.2f, 0.5f, 0.0f, -1.0f,
+ 1.2f, -0.5f, 0.3f, -0.9f,
+ },
+ {
+ 1.0f, 0.1f, -1.1f, 0.6f,
+ 0.8f, -1.2f, -1.1f, 0.7f,
+ },
+};
+static const float s_constInMat2x3[2][6] =
+{
+ {
+ -0.6f, -0.1f,
+ -0.7f, -1.2f,
+ -0.2f, 0.0f,
+ },
+ {
+ 1.1f, 0.6f,
+ 0.8f, 1.0f,
+ 0.7f, 0.1f,
+ },
+};
+static const float s_constInMat3x3[2][9] =
+{
+ {
+ -0.2f, 1.1f, 1.2f,
+ -1.0f, 1.2f, 0.5f,
+ 0.7f, -0.2f, 1.0f,
+ },
+ {
+ -0.1f, -0.1f, 0.1f,
+ -0.1f, -0.2f, 1.0f,
+ -0.5f, 0.1f, -0.4f,
+ },
+};
+static const float s_constInMat4x3[2][12] =
+{
+ {
+ -0.9f, 0.0f, 0.6f, 0.2f,
+ 0.9f, -0.1f, -0.3f, -0.7f,
+ -0.1f, 0.1f, 1.0f, 0.0f,
+ },
+ {
+ 0.5f, 0.7f, 0.7f, 1.2f,
+ 1.1f, 0.1f, 1.0f, -1.0f,
+ -0.2f, -0.2f, -0.3f, -0.5f,
+ },
+};
+static const float s_constInMat2x4[2][8] =
+{
+ {
+ -0.6f, -1.1f,
+ -0.6f, -0.6f,
+ -0.2f, -0.6f,
+ -0.1f, -0.1f,
+ },
+ {
+ -1.2f, -1.0f,
+ 0.7f, -1.0f,
+ 0.7f, 0.7f,
+ -0.4f, -0.3f,
+ },
+};
+static const float s_constInMat3x4[2][12] =
+{
+ {
+ 0.6f, -0.4f, 1.2f,
+ 0.9f, 0.8f, 0.4f,
+ 1.1f, 0.3f, 0.5f,
+ -0.2f, 0.0f, 1.1f,
+ },
+ {
+ -0.8f, 1.2f, -0.2f,
+ -1.1f, -0.9f, -0.5f,
+ -1.2f, 1.0f, 1.2f,
+ 0.1f, -0.7f, -0.5f,
+ },
+};
+static const float s_constInMat4x4[2][16] =
+{
+ {
+ 0.3f, 0.9f, -0.2f, 1.0f,
+ -0.4f, -0.6f, 0.6f, -1.0f,
+ -0.9f, -0.1f, 0.3f, -0.2f,
+ -0.3f, -0.9f, 1.0f, 0.1f,
+ },
+ {
+ 0.4f, -0.7f, -0.8f, 0.7f,
+ -0.4f, -0.8f, 0.6f, -0.3f,
+ 0.7f, -1.0f, 0.1f, -0.3f,
+ 0.2f, 0.6f, 0.4f, -1.0f,
+ },
+};
+
+namespace MatrixCaseUtils
+{
+
+enum InputType
+{
+ INPUTTYPE_CONST = 0,
+ INPUTTYPE_UNIFORM,
+ INPUTTYPE_DYNAMIC,
+
+ INPUTTYPE_LAST
+};
+
+struct ShaderInput
+{
+ ShaderInput (InputType inputType_, DataType dataType_, Precision precision_)
+ : inputType (inputType_)
+ , dataType (dataType_)
+ , precision (precision_)
+ {
+ }
+
+ InputType inputType;
+ DataType dataType;
+ Precision precision;
+};
+
+enum MatrixOp
+{
+ OP_ADD = 0,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_COMP_MUL,
+ OP_OUTER_PRODUCT,
+ OP_TRANSPOSE,
+ OP_INVERSE,
+ OP_DETERMINANT,
+ OP_UNARY_PLUS,
+ OP_NEGATION,
+ OP_PRE_INCREMENT,
+ OP_PRE_DECREMENT,
+ OP_POST_INCREMENT,
+ OP_POST_DECREMENT,
+ OP_ADD_INTO,
+ OP_SUBTRACT_FROM,
+ OP_MULTIPLY_INTO,
+ OP_DIVIDE_INTO,
+ OP_LAST
+};
+
+// Type traits.
+
+template <int DataT>
+struct TypeTraits;
+
+#define DECLARE_TYPE_TRAIT(DATATYPE, TYPE) \
+template<> \
+struct TypeTraits<DATATYPE> { \
+ typedef TYPE Type; \
+}
+
+DECLARE_TYPE_TRAIT(TYPE_FLOAT, float);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2, tcu::Vec2);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3, tcu::Vec3);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4, tcu::Vec4);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X3, tcu::Mat2x3);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X4, tcu::Mat2x4);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X2, tcu::Mat3x2);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X4, tcu::Mat3x4);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X2, tcu::Mat4x2);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X3, tcu::Mat4x3);
+DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4);
+
+// Operation info
+
+enum OperationType
+{
+ OPERATIONTYPE_BINARY_OPERATOR = 0,
+ OPERATIONTYPE_BINARY_FUNCTION,
+ OPERATIONTYPE_UNARY_PREFIX_OPERATOR,
+ OPERATIONTYPE_UNARY_POSTFIX_OPERATOR,
+ OPERATIONTYPE_UNARY_FUNCTION,
+ OPERATIONTYPE_ASSIGNMENT,
+
+ OPERATIONTYPE_LAST
+};
+
+static const char* getOperationName (MatrixOp op)
+{
+ switch (op)
+ {
+ case OP_ADD: return "+";
+ case OP_SUB: return "-";
+ case OP_MUL: return "*";
+ case OP_DIV: return "/";
+ case OP_COMP_MUL: return "matrixCompMult";
+ case OP_OUTER_PRODUCT: return "outerProduct";
+ case OP_TRANSPOSE: return "transpose";
+ case OP_INVERSE: return "inverse";
+ case OP_DETERMINANT: return "determinant";
+ case OP_UNARY_PLUS: return "+";
+ case OP_NEGATION: return "-";
+ case OP_PRE_INCREMENT: return "++";
+ case OP_PRE_DECREMENT: return "--";
+ case OP_POST_INCREMENT: return "++";
+ case OP_POST_DECREMENT: return "--";
+ case OP_ADD_INTO: return "+=";
+ case OP_SUBTRACT_FROM: return "-=";
+ case OP_MULTIPLY_INTO: return "*=";
+ case OP_DIVIDE_INTO: return "/=";
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ return "";
+ }
+}
+
+static OperationType getOperationType (MatrixOp op)
+{
+ switch (op)
+ {
+ case OP_ADD: return OPERATIONTYPE_BINARY_OPERATOR;
+ case OP_SUB: return OPERATIONTYPE_BINARY_OPERATOR;
+ case OP_MUL: return OPERATIONTYPE_BINARY_OPERATOR;
+ case OP_DIV: return OPERATIONTYPE_BINARY_OPERATOR;
+ case OP_COMP_MUL: return OPERATIONTYPE_BINARY_FUNCTION;
+ case OP_OUTER_PRODUCT: return OPERATIONTYPE_BINARY_FUNCTION;
+ case OP_TRANSPOSE: return OPERATIONTYPE_UNARY_FUNCTION;
+ case OP_INVERSE: return OPERATIONTYPE_UNARY_FUNCTION;
+ case OP_DETERMINANT: return OPERATIONTYPE_UNARY_FUNCTION;
+ case OP_UNARY_PLUS: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
+ case OP_NEGATION: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
+ case OP_PRE_INCREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
+ case OP_PRE_DECREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
+ case OP_POST_INCREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
+ case OP_POST_DECREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
+ case OP_ADD_INTO: return OPERATIONTYPE_ASSIGNMENT;
+ case OP_SUBTRACT_FROM: return OPERATIONTYPE_ASSIGNMENT;
+ case OP_MULTIPLY_INTO: return OPERATIONTYPE_ASSIGNMENT;
+ case OP_DIVIDE_INTO: return OPERATIONTYPE_ASSIGNMENT;
+ default:
+ DE_ASSERT(DE_FALSE);
+ return OPERATIONTYPE_LAST;
+ }
+}
+
+enum TestMatrixType
+{
+ TESTMATRIXTYPE_DEFAULT = 0,
+ TESTMATRIXTYPE_NEGATED,
+ TESTMATRIXTYPE_INCREMENTED,
+ TESTMATRIXTYPE_DECREMENTED,
+ TESTMATRIXTYPE_NEGATED_INCREMENTED,
+ TESTMATRIXTYPE_INCREMENTED_LESS,
+
+ TESTMATRIXTYPE_LAST
+};
+
+static TestMatrixType getOperationTestMatrixType (MatrixOp op)
+{
+ switch(op)
+ {
+ case OP_ADD: return TESTMATRIXTYPE_DEFAULT;
+ case OP_SUB: return TESTMATRIXTYPE_DEFAULT;
+ case OP_MUL: return TESTMATRIXTYPE_DEFAULT;
+ case OP_DIV: return TESTMATRIXTYPE_DEFAULT;
+ case OP_COMP_MUL: return TESTMATRIXTYPE_DEFAULT;
+ case OP_OUTER_PRODUCT: return TESTMATRIXTYPE_DEFAULT;
+ case OP_TRANSPOSE: return TESTMATRIXTYPE_DEFAULT;
+ case OP_INVERSE: return TESTMATRIXTYPE_DEFAULT;
+ case OP_DETERMINANT: return TESTMATRIXTYPE_DEFAULT;
+ case OP_UNARY_PLUS: return TESTMATRIXTYPE_DECREMENTED;
+ case OP_NEGATION: return TESTMATRIXTYPE_NEGATED_INCREMENTED;
+ case OP_PRE_INCREMENT: return TESTMATRIXTYPE_NEGATED;
+ case OP_PRE_DECREMENT: return TESTMATRIXTYPE_INCREMENTED;
+ case OP_POST_INCREMENT: return TESTMATRIXTYPE_NEGATED;
+ case OP_POST_DECREMENT: return TESTMATRIXTYPE_DEFAULT;
+ case OP_ADD_INTO: return TESTMATRIXTYPE_DEFAULT;
+ case OP_SUBTRACT_FROM: return TESTMATRIXTYPE_INCREMENTED_LESS;
+ case OP_MULTIPLY_INTO: return TESTMATRIXTYPE_NEGATED;
+ case OP_DIVIDE_INTO: return TESTMATRIXTYPE_DECREMENTED;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ return TESTMATRIXTYPE_LAST;
+ }
+}
+
+static bool isOperationBinary (MatrixOp op)
+{
+ return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR ||
+ getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION ||
+ getOperationType(op) == OPERATIONTYPE_ASSIGNMENT;
+}
+
+static bool isOperationMatrixScalar (MatrixOp op)
+{
+ return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
+}
+
+static bool isOperationMatrixVector (MatrixOp op)
+{
+ return op == OP_MUL;
+}
+
+static bool isOperationArithmeticMatrixMatrix (MatrixOp op)
+{
+ return op == OP_MUL;
+}
+
+static bool isOperationComponentwiseMatrixMatrix (MatrixOp op)
+{
+ return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL;
+}
+
+static bool isOperationVectorVector (MatrixOp op)
+{
+ return op == OP_OUTER_PRODUCT;
+}
+
+static bool isOperationUnaryAnyMatrix (MatrixOp op)
+{
+ return op == OP_TRANSPOSE ||
+ op == OP_UNARY_PLUS ||
+ op == OP_NEGATION ||
+ op == OP_PRE_INCREMENT ||
+ op == OP_PRE_DECREMENT ||
+ op == OP_POST_INCREMENT ||
+ op == OP_POST_DECREMENT;
+}
+
+static bool isOperationUnarySymmetricMatrix (MatrixOp op)
+{
+ return op == OP_INVERSE || op == OP_DETERMINANT;
+}
+
+static bool isOperationValueModifying (MatrixOp op)
+{
+ return op == OP_PRE_INCREMENT ||
+ op == OP_PRE_DECREMENT ||
+ op == OP_POST_INCREMENT ||
+ op == OP_POST_DECREMENT;
+}
+
+static bool isOperationAssignment (MatrixOp op)
+{
+ return op == OP_ADD_INTO ||
+ op == OP_SUBTRACT_FROM ||
+ op == OP_MULTIPLY_INTO ||
+ op == OP_DIVIDE_INTO;
+}
+
+static bool isOperationAssignmentAnyMatrix (MatrixOp op)
+{
+ return op == OP_ADD_INTO ||
+ op == OP_SUBTRACT_FROM ||
+ op == OP_DIVIDE_INTO;
+}
+
+static bool isOperationAssignmentSymmetricMatrix (MatrixOp op)
+{
+ return op == OP_MULTIPLY_INTO;
+}
+
+// Operation nature
+
+enum OperationNature
+{
+ OPERATIONNATURE_PURE = 0,
+ OPERATIONNATURE_MUTATING,
+ OPERATIONNATURE_ASSIGNMENT,
+
+ OPERATIONNATURE_LAST
+};
+
+static OperationNature getOperationNature (MatrixOp op)
+{
+ if (isOperationAssignment(op))
+ return OPERATIONNATURE_ASSIGNMENT;
+
+ if (isOperationValueModifying(op))
+ return OPERATIONNATURE_MUTATING;
+
+ return OPERATIONNATURE_PURE;
+}
+
+// Input value loader.
+
+template <int InputT, int DataT>
+typename TypeTraits<DataT>::Type getInputValue (const ShaderEvalContext& evalCtx, int inputNdx);
+
+template <> inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx]; }
+template <> inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx]; }
+template <> inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx]; }
+template <> inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx]; }
+
+template <> inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2(s_constInMat2x2[inputNdx]); }
+template <> inline tcu::Mat2x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x3(s_constInMat2x3[inputNdx]); }
+template <> inline tcu::Mat2x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x4(s_constInMat2x4[inputNdx]); }
+template <> inline tcu::Mat3x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x2(s_constInMat3x2[inputNdx]); }
+template <> inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3(s_constInMat3x3[inputNdx]); }
+template <> inline tcu::Mat3x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x4(s_constInMat3x4[inputNdx]); }
+template <> inline tcu::Mat4x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x2(s_constInMat4x2[inputNdx]); }
+template <> inline tcu::Mat4x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x3(s_constInMat4x3[inputNdx]); }
+template <> inline tcu::Mat4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4(s_constInMat4x4[inputNdx]); }
+
+template <> inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x(); }
+template <> inline tcu::Vec2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1); }
+template <> inline tcu::Vec3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1, 2); }
+template <> inline tcu::Vec4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1, 2, 3); }
+
+template <> inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat2 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1));
+ return m;
+}
+
+template <> inline tcu::Mat2x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X3> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat2x3 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
+ return m;
+}
+
+template <> inline tcu::Mat2x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X4> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat2x4 m;
+ m.setColumn(0, evalCtx.in[0]);
+ m.setColumn(1, evalCtx.in[1]);
+ return m;
+}
+
+template <> inline tcu::Mat3x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X2> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat3x2 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1));
+ m.setColumn(2, evalCtx.in[2].swizzle(0,1));
+ return m;
+}
+
+template <> inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat3 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
+ m.setColumn(2, evalCtx.in[2].swizzle(0,1,2));
+ return m;
+}
+
+template <> inline tcu::Mat3x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X4> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat3x4 m;
+ m.setColumn(0, evalCtx.in[0]);
+ m.setColumn(1, evalCtx.in[1]);
+ m.setColumn(2, evalCtx.in[2]);
+ return m;
+}
+
+template <> inline tcu::Mat4x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X2> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat4x2 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1));
+ m.setColumn(2, evalCtx.in[2].swizzle(0,1));
+ m.setColumn(3, evalCtx.in[3].swizzle(0,1));
+ return m;
+}
+
+template <> inline tcu::Mat4x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X3> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat4x3 m;
+ m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
+ m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
+ m.setColumn(2, evalCtx.in[2].swizzle(0,1,2));
+ m.setColumn(3, evalCtx.in[3].swizzle(0,1,2));
+ return m;
+}
+
+template <> inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx)
+{
+ DE_UNREF(inputNdx); // Not used.
+ tcu::Mat4 m;
+ m.setColumn(0, evalCtx.in[0]);
+ m.setColumn(1, evalCtx.in[1]);
+ m.setColumn(2, evalCtx.in[2]);
+ m.setColumn(3, evalCtx.in[3]);
+ return m;
+}
+
+// Reduction from expression result to vec3.
+
+inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; }
+inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x3& value) { return value.getColumn(0) + value.getColumn(1); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat3x2& value) { return tcu::Vec3(value(0,0)+value(1,0), value(0,1)+value(1,1), value(0,2)+value(1,2)); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat3x4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3) + value.getColumn(2).swizzle(2,3,0); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat4x2& value) { return tcu::Vec3(value(0,0)+value(1,0)+value(0,3), value(0,1)+value(1,1)+value(1,3), value(0,2)+value(1,2)); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat4x3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2) + value.getColumn(3); }
+inline tcu::Vec3 reduceToVec3 (const tcu::Mat4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3) + value.getColumn(2).swizzle(2,3,0) + value.getColumn(3).swizzle(3,0,1); }
+
+// matrixCompMult
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Rows, Cols> matrixCompMult (const tcu::Matrix<T, Rows, Cols>& a, const tcu::Matrix<T, Rows, Cols>& b)
+{
+ tcu::Matrix<T, Rows, Cols> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(r,c) = a(r,c) * b(r, c);
+
+ return retVal;
+}
+
+// transpose
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Cols, Rows> transpose (const tcu::Matrix<T, Rows, Cols>& mat)
+{
+ tcu::Matrix<T, Cols, Rows> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(c, r) = mat(r, c);
+
+ return retVal;
+}
+
+// outerProduct
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Cols, Rows> outerProduct (const tcu::Vector<T, Cols>& a, const tcu::Vector<T, Rows>& b)
+{
+ tcu::Matrix<T, Rows, Cols> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(r,c) = a[c] * b[r];
+
+ return transpose(retVal); // to gl-form (column-major)
+}
+
+// Determinant
+
+template <int Size>
+float determinant (const tcu::Matrix<float, Size, Size>& mat);
+
+template <>
+float determinant<2> (const tcu::Matrix<float, 2, 2>& mat)
+{
+ return mat(0,0) * mat(1,1) - mat(1,0) * mat(0,1);
+}
+
+template <>
+float determinant<3> (const tcu::Matrix<float, 3, 3>& mat)
+{
+ return + mat(0,0) * mat(1,1) * mat(2,2)
+ + mat(0,1) * mat(1,2) * mat(2,0)
+ + mat(0,2) * mat(1,0) * mat(2,1)
+ - mat(0,0) * mat(1,2) * mat(2,1)
+ - mat(0,1) * mat(1,0) * mat(2,2)
+ - mat(0,2) * mat(1,1) * mat(2,0);
+}
+
+template <>
+float determinant<4> (const tcu::Matrix<float, 4, 4>& mat)
+{
+ const float minorMatrices[4][3*3] =
+ {
+ {
+ mat(1,1), mat(2,1), mat(3,1),
+ mat(1,2), mat(2,2), mat(3,2),
+ mat(1,3), mat(2,3), mat(3,3),
+ },
+ {
+ mat(1,0), mat(2,0), mat(3,0),
+ mat(1,2), mat(2,2), mat(3,2),
+ mat(1,3), mat(2,3), mat(3,3),
+ },
+ {
+ mat(1,0), mat(2,0), mat(3,0),
+ mat(1,1), mat(2,1), mat(3,1),
+ mat(1,3), mat(2,3), mat(3,3),
+ },
+ {
+ mat(1,0), mat(2,0), mat(3,0),
+ mat(1,1), mat(2,1), mat(3,1),
+ mat(1,2), mat(2,2), mat(3,2),
+ }
+ };
+
+ return + mat(0,0) * determinant(tcu::Mat3(minorMatrices[0]))
+ - mat(0,1) * determinant(tcu::Mat3(minorMatrices[1]))
+ + mat(0,2) * determinant(tcu::Mat3(minorMatrices[2]))
+ - mat(0,3) * determinant(tcu::Mat3(minorMatrices[3]));
+}
+
+// Inverse
+
+template <int Size>
+tcu::Matrix<float, Size, Size> inverse (const tcu::Matrix<float, Size, Size>& mat);
+
+template <>
+tcu::Matrix<float, 2, 2> inverse<2> (const tcu::Matrix<float, 2, 2>& mat)
+{
+ const float det = determinant(mat);
+ tcu::Matrix<float, 2, 2> retVal;
+
+ DE_ASSERT(det != 0.0f);
+
+ retVal(0, 0) = mat(1, 1) / det;
+ retVal(0, 1) = -mat(0, 1) / det;
+ retVal(1, 0) = -mat(1, 0) / det;
+ retVal(1, 1) = mat(0, 0) / det;
+
+ return retVal;
+}
+
+template <>
+tcu::Matrix<float, 3, 3> inverse<3> (const tcu::Matrix<float, 3, 3>& mat)
+{
+ // Blockwise inversion
+
+ DE_ASSERT(determinant(mat) != 0.0f);
+
+ const float areaA[2*2] =
+ {
+ mat(0,0), mat(0,1),
+ mat(1,0), mat(1,1)
+ };
+ const float areaB[2] =
+ {
+ mat(0,2),
+ mat(1,2),
+ };
+ const float areaC[2] =
+ {
+ mat(2,0), mat(2,1),
+ };
+ const float areaD[1] =
+ {
+ mat(2,2)
+ };
+ const float nullField[4] = { 0.0f };
+
+ const tcu::Matrix<float, 2, 2> invA = inverse(tcu::Matrix<float, 2, 2>(areaA));
+ const tcu::Matrix<float, 2, 1> matB = tcu::Matrix<float, 2, 1>(areaB);
+ const tcu::Matrix<float, 1, 2> matC = tcu::Matrix<float, 1, 2>(areaC);
+ const tcu::Matrix<float, 1, 1> matD = tcu::Matrix<float, 1, 1>(areaD);
+
+ const float schurComplement = 1.0f / (matD - matC*invA*matB)(0,0);
+ const tcu::Matrix<float, 2, 2> zeroMat = Mat2(nullField);
+
+ const tcu::Matrix<float, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
+ const tcu::Matrix<float, 2, 1> blockB = (zeroMat-invA)*matB*schurComplement;
+ const tcu::Matrix<float, 1, 2> blockC = matC*invA*(-schurComplement);
+ const float blockD = schurComplement;
+
+ const float result[3*3] =
+ {
+ blockA(0,0), blockA(0,1), blockB(0,0),
+ blockA(1,0), blockA(1,1), blockB(1,0),
+ blockC(0,0), blockC(0,1), blockD,
+ };
+
+ return Mat3(result);
+}
+
+template <>
+tcu::Matrix<float, 4, 4> inverse<4> (const tcu::Matrix<float, 4, 4>& mat)
+{
+ // Blockwise inversion
+
+ DE_ASSERT(determinant(mat) != 0.0f);
+
+ const float areaA[2*2] =
+ {
+ mat(0,0), mat(0,1),
+ mat(1,0), mat(1,1)
+ };
+ const float areaB[2*2] =
+ {
+ mat(0,2), mat(0,3),
+ mat(1,2), mat(1,3)
+ };
+ const float areaC[2*2] =
+ {
+ mat(2,0), mat(2,1),
+ mat(3,0), mat(3,1)
+ };
+ const float areaD[2*2] =
+ {
+ mat(2,2), mat(2,3),
+ mat(3,2), mat(3,3)
+ };
+ const float nullField[4] = { 0.0f };
+
+ const tcu::Matrix<float, 2, 2> invA = inverse(Mat2(areaA));
+ const tcu::Matrix<float, 2, 2> matB = Mat2(areaB);
+ const tcu::Matrix<float, 2, 2> matC = Mat2(areaC);
+ const tcu::Matrix<float, 2, 2> matD = Mat2(areaD);
+
+ const tcu::Matrix<float, 2, 2> schurComplement = inverse(matD - matC*invA*matB);
+ const tcu::Matrix<float, 2, 2> zeroMat = Mat2(nullField);
+
+ const tcu::Matrix<float, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
+ const tcu::Matrix<float, 2, 2> blockB = (zeroMat-invA)*matB*schurComplement;
+ const tcu::Matrix<float, 2, 2> blockC = (zeroMat-schurComplement)*matC*invA;
+ const tcu::Matrix<float, 2, 2> blockD = schurComplement;
+
+ const float result[4*4] =
+ {
+ blockA(0,0), blockA(0,1), blockB(0,0), blockB(0,1),
+ blockA(1,0), blockA(1,1), blockB(1,0), blockB(1,1),
+ blockC(0,0), blockC(0,1), blockD(0,0), blockD(0,1),
+ blockC(1,0), blockC(1,1), blockD(1,0), blockD(1,1),
+ };
+
+ return Mat4(result);
+}
+
+// negate
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Rows, Cols> negate (const tcu::Matrix<T, Rows, Cols>& mat)
+{
+ tcu::Matrix<T, Rows, Cols> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(r,c) = -mat(r, c);
+
+ return retVal;
+}
+
+// increment/decrement
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Rows, Cols> increment (const tcu::Matrix<T, Rows, Cols>& mat)
+{
+ tcu::Matrix<T, Rows, Cols> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(r,c) = mat(r, c) + 1.0f;
+
+ return retVal;
+}
+
+template <typename T, int Rows, int Cols>
+tcu::Matrix<T, Rows, Cols> decrement (const tcu::Matrix<T, Rows, Cols>& mat)
+{
+ tcu::Matrix<T, Rows, Cols> retVal;
+
+ for (int r = 0; r < Rows; ++r)
+ for (int c = 0; c < Cols; ++c)
+ retVal(r,c) = mat(r, c) - 1.0f;
+
+ return retVal;
+}
+
+// Evaluator template.
+
+typedef void (*MatrixShaderEvalFunc) (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type);
+
+template <int Op, int In0DataType, int In1DataType>
+struct Evaluator;
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_ADD, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 + in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_SUB, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 - in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_MUL, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 * in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_DIV, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 / in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_COMP_MUL, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(matrixCompMult(in0, in1));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_OUTER_PRODUCT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(outerProduct(in0, in1));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_TRANSPOSE, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ evalCtx.color.xyz() = reduceToVec3(transpose(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_INVERSE, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ evalCtx.color.xyz() = reduceToVec3(inverse(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_DETERMINANT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ evalCtx.color.xyz() = Vec3(determinant(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_UNARY_PLUS, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ evalCtx.color.xyz() = reduceToVec3(in0);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_NEGATION, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ evalCtx.color.xyz() = reduceToVec3(negate(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_PRE_INCREMENT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+
+ // modifying reduction: sum modified value too
+ evalCtx.color.xyz() = reduceToVec3(increment(in0)) + reduceToVec3(increment(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_PRE_DECREMENT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+
+ // modifying reduction: sum modified value too
+ evalCtx.color.xyz() = reduceToVec3(decrement(in0)) + reduceToVec3(decrement(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_POST_INCREMENT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+
+ // modifying reduction: sum modified value too
+ evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(increment(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_POST_DECREMENT, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ DE_UNREF(in1Type);
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+
+ // modifying reduction: sum modified value too
+ evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(decrement(in0));
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_ADD_INTO, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 + in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_SUBTRACT_FROM, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 - in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_MULTIPLY_INTO, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 * in1);
+ }
+};
+
+template <int In0DataType, int In1DataType>
+struct Evaluator<OP_DIVIDE_INTO, In0DataType, In1DataType>
+{
+ static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
+ {
+ typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
+ : getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
+ typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
+ : getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
+ evalCtx.color.xyz() = reduceToVec3(in0 / in1);
+ }
+};
+
+MatrixShaderEvalFunc getEvalFunc (const ShaderInput& in0, const ShaderInput& in1, MatrixOp op)
+{
+ // Evaluator is selected based on op and input data types.
+ // For efficient lookup the types and op enums are packed together to form a 19-bit key:
+ // [18..14 OP] [13..7 TYPE0] [6..0 TYPE1]
+
+ DE_STATIC_ASSERT(TYPE_LAST <= (1<<7));
+ DE_STATIC_ASSERT(OP_LAST <= (1<<5));
+
+#define PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE) (((OP) << 14) | ((IN0DATATYPE) << 7) | (IN1DATATYPE))
+
+#define MAKE_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE) \
+ case PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE): \
+ return Evaluator<OP, IN0DATATYPE, IN1DATATYPE>::evaluate
+
+#define MAKE_SCALAR_OPS(IN0DATATYPE, IN1DATATYPE) \
+ MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE)
+
+#define MAKE_CWISE_OPS(IN0DATATYPE, IN1DATATYPE) \
+ MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE); \
+ MAKE_EVAL_CASE(OP_COMP_MUL, IN0DATATYPE, IN1DATATYPE)
+
+#define MAKE_MUL_OP(IN0DATATYPE, IN1DATATYPE) \
+ MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE)
+
+#define MAKE_VECVEC_OP(IN0DATATYPE, IN1DATATYPE) \
+ MAKE_EVAL_CASE(OP_OUTER_PRODUCT, IN0DATATYPE, IN1DATATYPE)
+
+#define MAKE_UNARY_OP(IN0DATATYPE) \
+ MAKE_EVAL_CASE(OP_TRANSPOSE, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_UNARY_PLUS, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_NEGATION, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_PRE_INCREMENT, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_PRE_DECREMENT, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_POST_INCREMENT, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_POST_DECREMENT, IN0DATATYPE, TYPE_LAST)
+
+#define MAKE_UNARY_SYMMETRIC_OP(IN0DATATYPE) \
+ MAKE_UNARY_OP(IN0DATATYPE); \
+ MAKE_EVAL_CASE(OP_DETERMINANT, IN0DATATYPE, TYPE_LAST); \
+ MAKE_EVAL_CASE(OP_INVERSE, IN0DATATYPE, TYPE_LAST)
+
+#define MAKE_ASSIGNMENT_OP(IN0DATATYPE) \
+ MAKE_EVAL_CASE(OP_ADD_INTO, IN0DATATYPE, IN0DATATYPE); \
+ MAKE_EVAL_CASE(OP_SUBTRACT_FROM, IN0DATATYPE, IN0DATATYPE); \
+ MAKE_EVAL_CASE(OP_DIVIDE_INTO, IN0DATATYPE, IN0DATATYPE)
+
+#define MAKE_ASSIGNMENT_SYMMETRIC_OP(IN0DATATYPE) \
+ MAKE_ASSIGNMENT_OP(IN0DATATYPE); \
+ MAKE_EVAL_CASE(OP_MULTIPLY_INTO, IN0DATATYPE, IN0DATATYPE)
+
+ switch (PACK_EVAL_CASE(op, in0.dataType, in1.dataType))
+ {
+ // Matrix-scalar.
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT);
+ MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT);
+
+ // Matrix-vector.
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_VEC2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_VEC2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_VEC3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_VEC3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_VEC4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_VEC4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4);
+
+ // Vector-matrix.
+ MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT2X3);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT2X4);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT3X2);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT3X4);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT4X2);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT4X3);
+ MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
+
+ // Matrix-matrix.
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT3X2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT4X2);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2X3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT3X2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT4X2);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT3X2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT4X2);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3X2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT2X3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT4X3);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT2X3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT4X3);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT2X3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT4X3);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4X2);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT2X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT3X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4X3);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT2X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT3X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4);
+
+ MAKE_CWISE_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT2X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT3X4);
+ MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
+
+ // Vector-vector.
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC2);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC3);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC4);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC2);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC3);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC4);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC2);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC3);
+ MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4);
+
+ // Unary Matrix.
+ MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT2X3);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT2X4);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT3X2);
+ MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT3X4);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT4X2);
+ MAKE_UNARY_OP(TYPE_FLOAT_MAT4X3);
+ MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
+
+ // Assignments
+ MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X3);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X4);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X2);
+ MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X4);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X2);
+ MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X3);
+ MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ return DE_NULL;
+ }
+
+#undef PACK_EVAL_CASE
+#undef MAKE_EVAL_CASE
+#undef MUL_OP
+#undef ALL_OPS
+#undef MAKE_MAT_SCALAR_VEC_CASES
+#undef MAKE_MAT_MAT_CASES
+}
+
+// Shader source format utilities.
+
+template <int Size>
+void writeVectorConstructor (std::ostream& str, const tcu::Vector<float, Size>& v)
+{
+ str << "vec" << Size << "(";
+ for (int ndx = 0; ndx < Size; ndx++)
+ {
+ if (ndx != 0)
+ str << ", ";
+ str << de::floatToString(v[ndx], 1);
+ }
+ str << ")";
+}
+
+template <int Cols, int Rows>
+void writeMatrixConstructor (std::ostream& str, const tcu::Matrix<float, Rows, Cols>& m)
+{
+ if (Rows == Cols)
+ str << "mat" << Cols;
+ else
+ str << "mat" << Cols << "x" << Rows;
+
+ str << "(";
+ for (int colNdx = 0; colNdx < Cols; colNdx++)
+ {
+ for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
+ {
+ if (rowNdx > 0 || colNdx > 0)
+ str << ", ";
+ str << de::floatToString(m(rowNdx, colNdx), 1);
+ }
+ }
+ str << ")";
+}
+
+} // MatrixCaseUtils
+
+using namespace MatrixCaseUtils;
+
+class MatrixShaderEvaluator : public ShaderEvaluator
+{
+public:
+ MatrixShaderEvaluator (MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1);
+
+ virtual void evaluate (ShaderEvalContext& evalCtx) const;
+
+private:
+ MatrixShaderEvalFunc m_matEvalFunc;
+ InputType m_inType0;
+ InputType m_inType1;
+};
+
+MatrixShaderEvaluator::MatrixShaderEvaluator (MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1)
+ : m_matEvalFunc (evalFunc)
+ , m_inType0 (inType0)
+ , m_inType1 (inType1)
+{
+}
+
+void MatrixShaderEvaluator::evaluate (ShaderEvalContext& evalCtx) const
+{
+ m_matEvalFunc(evalCtx, m_inType0, m_inType1);
+}
+
+
+BaseAttributeType getAttributeType(const glu::DataType dataType)
+{
+ switch(dataType)
+ {
+ case TYPE_FLOAT_MAT2: return MAT2;
+ case TYPE_FLOAT_MAT2X3: return MAT2x3;
+ case TYPE_FLOAT_MAT2X4: return MAT2x4;
+ case TYPE_FLOAT_MAT3X2: return MAT3x2;
+ case TYPE_FLOAT_MAT3: return MAT3;
+ case TYPE_FLOAT_MAT3X4: return MAT3x4;
+ case TYPE_FLOAT_MAT4X2: return MAT4x2;
+ case TYPE_FLOAT_MAT4X3: return MAT4x3;
+ case TYPE_FLOAT_MAT4: return MAT4;
+ default:
+ TCU_THROW(InternalError, "Not supported");
+ break;
+ }
+}
+
+// ShaderMatrixInstance
+
+class ShaderMatrixInstance : public ShaderRenderCaseInstance
+{
+public:
+ ShaderMatrixInstance (Context& context,
+ bool isVertex,
+ const ShaderEvaluator& evaluator,
+ const ShaderInput in0,
+ const ShaderInput in1,
+ const MatrixOp m_op);
+ virtual ~ShaderMatrixInstance (void);
+
+protected:
+ virtual void setupUniforms (const tcu::Vec4&);
+
+private:
+ void addMatrixUniform (deUint32 bindingLocation, DataType dataType, const float* dataPtr);
+
+ const ShaderInput m_in0;
+ const ShaderInput m_in1;
+ const MatrixOp m_op;
+};
+
+ShaderMatrixInstance::ShaderMatrixInstance (Context& context,
+ bool isVertex,
+ const ShaderEvaluator& evaluator,
+ const ShaderInput in0,
+ const ShaderInput in1,
+ const MatrixOp op)
+ : ShaderRenderCaseInstance (context, isVertex, evaluator, DE_NULL, DE_NULL)
+ , m_in0 (in0)
+ , m_in1 (in1)
+ , m_op (op)
+{
+ m_userAttribTransforms.resize(4);
+ for (int attribNdx = 0; attribNdx < 4; attribNdx++)
+ {
+ m_userAttribTransforms[attribNdx] = Mat4(0.0f);
+ m_userAttribTransforms[attribNdx]( 0, 3) = 0.2f; // !< prevent matrix*vec from going into zero (assuming vec.w != 0)
+ m_userAttribTransforms[attribNdx]( 1, 3) = 0.1f; // !<
+ m_userAttribTransforms[attribNdx]( 2, 3) = 0.4f + 0.15f * float(attribNdx); // !<
+ m_userAttribTransforms[attribNdx]( 3, 3) = 0.7f; // !<
+ m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
+ m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
+ m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
+ m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
+ }
+
+ // prevent bad reference cases such as black result images by fine-tuning used matrices
+ if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
+ {
+ for (int attribNdx = 0; attribNdx < 4; attribNdx++)
+ {
+ for (int row = 0; row < 4; row++)
+ for (int col = 0; col < 4; col++)
+ {
+ switch (getOperationTestMatrixType(m_op))
+ {
+ case TESTMATRIXTYPE_NEGATED:
+ m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
+ break;
+ case TESTMATRIXTYPE_INCREMENTED:
+ m_userAttribTransforms[attribNdx](row, col) += 0.3f;
+ break;
+ case TESTMATRIXTYPE_DECREMENTED:
+ m_userAttribTransforms[attribNdx](row, col) -= 0.3f;
+ break;
+ case TESTMATRIXTYPE_NEGATED_INCREMENTED:
+ m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col) + 0.3f;
+ break;
+ case TESTMATRIXTYPE_INCREMENTED_LESS:
+ m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
+ break;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ break;
+ }
+ }
+ }
+ }
+
+ int numInputs = isOperationBinary(m_op) ? 2 : 1;
+
+ for (int inNdx = 0; inNdx < numInputs; inNdx++)
+ {
+ const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
+
+ if (in.inputType == INPUTTYPE_DYNAMIC && isDataTypeMatrix(in.dataType))
+ {
+ useAttribute(4u + inNdx, getAttributeType(in.dataType));
+ }
+ }
+
+}
+
+ShaderMatrixInstance::~ShaderMatrixInstance (void)
+{
+}
+
+void ShaderMatrixInstance::addMatrixUniform(deUint32 bindingLocation, DataType dataType, const float *dataPtr)
+{
+ Mat4 result;
+ const deUint32 matrixSize = sizeof(float) * 4 *4 ;
+
+ switch(dataType)
+ {
+ case TYPE_FLOAT_MAT2:
+ {
+ Mat2 matrix = transpose(Mat2(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT2X3:
+ {
+ Mat3x2 matrix = transpose(Mat2x3(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT2X4:
+ {
+ Mat4x2 matrix = transpose(Mat2x4(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT3X2:
+ {
+ Mat2x3 matrix = transpose(Mat3x2(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT3:
+ {
+ Mat3 matrix = transpose(Mat3(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT3X4:
+ {
+ Mat4x3 matrix = transpose(Mat3x4(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT4X2:
+ {
+ Mat2x4 matrix = transpose(Mat4x2(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ result.setRow(3, matrix.getRow(3).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT4X3:
+ {
+ Mat3x4 matrix = transpose(Mat4x3(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ result.setRow(3, matrix.getRow(3).toWidth<4>());
+ break;
+ }
+ case TYPE_FLOAT_MAT4:
+ {
+ Mat4 matrix = transpose(Mat4(dataPtr));
+ result.setRow(0, matrix.getRow(0).toWidth<4>());
+ result.setRow(1, matrix.getRow(1).toWidth<4>());
+ result.setRow(2, matrix.getRow(2).toWidth<4>());
+ result.setRow(3, matrix.getRow(3).toWidth<4>());
+ break;
+ }
+ default:
+ DE_ASSERT(false);
+ break;
+ }
+
+ addUniform(bindingLocation, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, matrixSize, result.getColumnMajorData().getPtr());
+}
+
+void ShaderMatrixInstance::setupUniforms (const tcu::Vec4&)
+{
+ const int numInputs = isOperationBinary(m_op) ? 2 : 1;
+ deUint32 uniformBinding = 0;
+
+ for (int inNdx = 0; inNdx < numInputs; inNdx++)
+ {
+ const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
+
+ if (in.inputType == INPUTTYPE_UNIFORM)
+ {
+ switch (in.dataType)
+ {
+ case TYPE_FLOAT: addUniform(uniformBinding, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(float), &s_constInFloat[inNdx]); break;
+ case TYPE_FLOAT_VEC2: addUniform(uniformBinding, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, s_constInVec2[inNdx].getPtr()); break;
+ case TYPE_FLOAT_VEC3: addUniform(uniformBinding, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, s_constInVec3[inNdx].getPtr()); break;
+ case TYPE_FLOAT_VEC4: addUniform(uniformBinding, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, s_constInVec4[inNdx].getPtr()); break;
+ // \note GLES3 supports transpose in matrix upload.
+ case TYPE_FLOAT_MAT2: addMatrixUniform(uniformBinding, in.dataType, s_constInMat2x2[inNdx]); break;
+ case TYPE_FLOAT_MAT2X3: addMatrixUniform(uniformBinding, in.dataType, s_constInMat2x3[inNdx]); break;
+ case TYPE_FLOAT_MAT2X4: addMatrixUniform(uniformBinding, in.dataType, s_constInMat2x4[inNdx]); break;
+ case TYPE_FLOAT_MAT3X2: addMatrixUniform(uniformBinding, in.dataType, s_constInMat3x2[inNdx]); break;
+ case TYPE_FLOAT_MAT3: addMatrixUniform(uniformBinding, in.dataType, s_constInMat3x3[inNdx]); break;
+ case TYPE_FLOAT_MAT3X4: addMatrixUniform(uniformBinding, in.dataType, s_constInMat3x4[inNdx]); break;
+ case TYPE_FLOAT_MAT4X2: addMatrixUniform(uniformBinding, in.dataType, s_constInMat4x2[inNdx]); break;
+ case TYPE_FLOAT_MAT4X3: addMatrixUniform(uniformBinding, in.dataType, s_constInMat4x3[inNdx]); break;
+ case TYPE_FLOAT_MAT4: addMatrixUniform(uniformBinding, in.dataType, s_constInMat4x4[inNdx]); break;
+ default:
+ DE_ASSERT(false);
+ }
+ uniformBinding++;
+ }
+ }
+}
+
+// ShaderMatrixCase
+
+class ShaderMatrixCase : public ShaderRenderCase
+{
+public:
+ ShaderMatrixCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& desc,
+ const ShaderInput& in0,
+ const ShaderInput& in1,
+ const MatrixOp op,
+ bool isVertexCase);
+ ~ShaderMatrixCase (void);
+
+ virtual TestInstance* createInstance (Context& context) const;
+
+protected:
+ void setupShader (void);
+ std::string genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName);
+
+private:
+ const ShaderInput m_in0;
+ const ShaderInput m_in1;
+ const MatrixOp m_op;
+};
+
+ShaderMatrixCase::ShaderMatrixCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& desc,
+ const ShaderInput& in0,
+ const ShaderInput& in1,
+ MatrixOp op,
+ bool isVertexCase)
+ : ShaderRenderCase (testCtx,
+ name,
+ desc,
+ isVertexCase,
+ new MatrixShaderEvaluator(getEvalFunc(in0, in1, op), in0.inputType, in1.inputType),
+ DE_NULL /* uniform setup */,
+ DE_NULL /* attribute setup */)
+ , m_in0 (in0)
+ , m_in1 (in1)
+ , m_op (op)
+{
+ setupShader();
+}
+
+ShaderMatrixCase::~ShaderMatrixCase (void)
+{
+}
+
+TestInstance* ShaderMatrixCase::createInstance (Context& context) const
+{
+ return new ShaderMatrixInstance(context, m_isVertexCase, *m_evaluator, m_in0, m_in1, m_op);
+}
+
+void ShaderMatrixCase::setupShader (void)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = m_isVertexCase ? vtx : frag;
+
+ bool isInDynMat0 = isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
+ bool isInDynMat1 = isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
+ string inValue0;
+ string inValue1;
+ DataType resultType = TYPE_LAST;
+ Precision resultPrec = m_in0.precision;
+ vector<string> passVars;
+ int numInputs = (isOperationBinary(m_op)) ? (2) : (1);
+
+ std::string operationValue0;
+ std::string operationValue1;
+
+ DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
+ DE_UNREF(isInDynMat0 && isInDynMat1);
+
+ // Compute result type.
+ if (m_op == OP_MUL && isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
+ {
+ resultType = getDataTypeMatrix(getDataTypeMatrixNumColumns(m_in1.dataType), getDataTypeMatrixNumRows(m_in0.dataType));
+ }
+ else if (m_op == OP_OUTER_PRODUCT)
+ {
+ resultType = getDataTypeMatrix(getDataTypeScalarSize(m_in1.dataType), getDataTypeScalarSize(m_in0.dataType));
+ }
+ else if (m_op == OP_TRANSPOSE)
+ {
+ resultType = getDataTypeMatrix(getDataTypeMatrixNumRows(m_in0.dataType), getDataTypeMatrixNumColumns(m_in0.dataType));
+ }
+ else if (m_op == OP_INVERSE)
+ {
+ resultType = m_in0.dataType;
+ }
+ else if (m_op == OP_DETERMINANT)
+ {
+ resultType = TYPE_FLOAT;
+ }
+ else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
+ getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
+ {
+ resultType = m_in0.dataType;
+ }
+ else if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
+ {
+ DE_ASSERT(m_in0.dataType == m_in1.dataType);
+ resultType = m_in0.dataType;
+ }
+ else if (isDataTypeMatrix(m_in0.dataType) || isDataTypeMatrix(m_in1.dataType))
+ {
+ int matNdx = isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
+ DataType matrixType = matNdx == 0 ? m_in0.dataType : m_in1.dataType;
+ DataType otherType = matNdx == 0 ? m_in1.dataType : m_in0.dataType;
+
+ if (otherType == TYPE_FLOAT)
+ resultType = matrixType;
+ else
+ {
+ DE_ASSERT(isDataTypeVector(otherType));
+ resultType = getDataTypeFloatVec(matNdx == 0 ? getDataTypeMatrixNumRows(matrixType) : getDataTypeMatrixNumColumns(matrixType));
+ }
+ }
+ else
+ {
+ DE_ASSERT(DE_FALSE);
+ }
+
+ static const std::string header =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n";
+
+ vtx << header;
+ frag << header;
+
+ vtx << "layout(location = 0) in highp vec4 a_position;\n";
+ frag << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+ if (m_isVertexCase)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 v_color;\n";
+ }
+
+ // Input declarations.
+ deUint32 uniformBinding = 0;
+ deUint32 padding = 0;
+ for (int inNdx = 0; inNdx < numInputs; inNdx++)
+ {
+ const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
+ const char* precName = getPrecisionName(in.precision);
+ const char* typeName = getDataTypeName(in.dataType);
+ string& inValue = inNdx > 0 ? inValue1 : inValue0;
+
+ if (in.inputType == INPUTTYPE_DYNAMIC)
+ {
+ if (isDataTypeMatrix(in.dataType))
+ {
+ vtx << "layout(location = " << 4 + inNdx + padding << ") in " << precName << " " << typeName << " a_";
+ // a_matN, v_matN
+ vtx << typeName << ";\n";
+ if (!m_isVertexCase)
+ {
+ vtx << "layout(location = " << 1 + inNdx + padding << ") out " << precName << " " << typeName << " v_" << typeName << ";\n";
+ frag << "layout(location = " << 1 + inNdx + padding << ") in " << precName << " " << typeName << " v_" << typeName << ";\n";
+ passVars.push_back(typeName);
+ }
+
+ inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
+ padding += getDataTypeMatrixNumColumns(in.dataType);
+ }
+ else
+ {
+ // a_coords, v_coords
+ vtx << "layout(location = 1) in " << precName << " " << typeName << " a_coords;\n";
+ if (!m_isVertexCase)
+ {
+ vtx << "layout(location = " << 1 + padding << ") out " << precName << " " << typeName << " v_coords;\n";
+ frag << "layout(location = " << 1 + padding << ") in " << precName << " " << typeName << " v_coords;\n";
+ passVars.push_back("coords");
+ }
+
+ inValue = m_isVertexCase ? "a_coords" : "v_coords";
+ }
+ }
+ else if (in.inputType == INPUTTYPE_UNIFORM)
+ {
+ op << "layout(std140, set = 0, binding = " << uniformBinding++ << ") uniform buffer"<< inNdx <<" { " << precName << " " << typeName << " u_in" << inNdx << "; };\n";
+ inValue = string("u_in") + de::toString(inNdx);
+ }
+ else if (in.inputType == INPUTTYPE_CONST)
+ {
+ op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
+
+ // Generate declaration.
+ switch (in.dataType)
+ {
+ case TYPE_FLOAT: op << de::floatToString(s_constInFloat[inNdx], 1); break;
+ case TYPE_FLOAT_VEC2: writeVectorConstructor<2>(op, s_constInVec2[inNdx]); break;
+ case TYPE_FLOAT_VEC3: writeVectorConstructor<3>(op, s_constInVec3[inNdx]); break;
+ case TYPE_FLOAT_VEC4: writeVectorConstructor<4>(op, s_constInVec4[inNdx]); break;
+ case TYPE_FLOAT_MAT2: writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2x2[inNdx])); break;
+ case TYPE_FLOAT_MAT2X3: writeMatrixConstructor<2, 3>(op, Mat2x3(s_constInMat2x3[inNdx])); break;
+ case TYPE_FLOAT_MAT2X4: writeMatrixConstructor<2, 4>(op, Mat2x4(s_constInMat2x4[inNdx])); break;
+ case TYPE_FLOAT_MAT3X2: writeMatrixConstructor<3, 2>(op, Mat3x2(s_constInMat3x2[inNdx])); break;
+ case TYPE_FLOAT_MAT3: writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3x3[inNdx])); break;
+ case TYPE_FLOAT_MAT3X4: writeMatrixConstructor<3, 4>(op, Mat3x4(s_constInMat3x4[inNdx])); break;
+ case TYPE_FLOAT_MAT4X2: writeMatrixConstructor<4, 2>(op, Mat4x2(s_constInMat4x2[inNdx])); break;
+ case TYPE_FLOAT_MAT4X3: writeMatrixConstructor<4, 3>(op, Mat4x3(s_constInMat4x3[inNdx])); break;
+ case TYPE_FLOAT_MAT4: writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4x4[inNdx])); break;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ }
+
+ op << ";\n";
+
+ inValue = string("in") + de::toString(inNdx);
+ }
+ }
+
+ vtx << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = a_position;\n";
+ frag << "\n"
+ << "void main (void)\n"
+ << "{\n";
+
+ if (m_isVertexCase)
+ frag << " dEQP_FragColor = v_color;\n";
+ else
+ {
+ for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
+ vtx << " v_" << *copyIter << " = " << "a_" << *copyIter << ";\n";
+ }
+
+ // Operation.
+
+ switch (getOperationNature(m_op))
+ {
+ case OPERATIONNATURE_PURE:
+ DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
+
+ operationValue0 = inValue0;
+ operationValue1 = inValue1;
+ break;
+
+ case OPERATIONNATURE_MUTATING:
+ DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
+
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0 << ";\n";
+
+ operationValue0 = "tmpValue";
+ operationValue1 = inValue1;
+ break;
+
+ case OPERATIONNATURE_ASSIGNMENT:
+ DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
+
+ operationValue0 = inValue0;
+ operationValue1 = inValue1;
+ break;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ }
+
+ switch (getOperationType(m_op))
+ {
+ case OPERATIONTYPE_BINARY_OPERATOR:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
+ break;
+
+ case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
+ break;
+
+ case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
+ break;
+
+ case OPERATIONTYPE_BINARY_FUNCTION:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
+ break;
+
+ case OPERATIONTYPE_UNARY_FUNCTION:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ");\n";
+ break;
+
+ case OPERATIONTYPE_ASSIGNMENT:
+ op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << ";\n";
+ op << " res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
+ break;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ }
+
+ // Reduction to vec3 (rgb). Check the used value too if it was modified
+ op << " " << (m_isVertexCase ? "v_color" : "dEQP_FragColor") << " = ";
+
+ if (isOperationValueModifying(m_op))
+ op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4(" << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
+ else
+ op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ m_vertShaderSource = vtx.str();
+ m_fragShaderSource = frag.str();
+}
+
+std::string ShaderMatrixCase::genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName)
+{
+ std::ostringstream op;
+
+ switch (matType)
+ {
+ case TYPE_FLOAT: op << varName << ", " << varName << ", " << varName << ""; break;
+ case TYPE_FLOAT_VEC2: op << varName << ".x, " << varName << ".y, " << varName << ".x"; break;
+ case TYPE_FLOAT_VEC3: op << varName << ""; break;
+ case TYPE_FLOAT_VEC4: op << varName << ".x, " << varName << ".y, " << varName << ".z+" << varName << ".w"; break;
+ case TYPE_FLOAT_MAT2: op << varName << "[0][0], " << varName << "[1][0], " << varName << "[0][1]+" << varName << "[1][1]"; break;
+ case TYPE_FLOAT_MAT2X3: op << varName << "[0] + " << varName << "[1]"; break;
+ case TYPE_FLOAT_MAT2X4: op << varName << "[0].xyz + " << varName << "[1].yzw"; break;
+ case TYPE_FLOAT_MAT3X2: op << varName << "[0][0]+" << varName << "[0][1], " << varName << "[1][0]+" << varName << "[1][1], " << varName << "[2][0]+" << varName << "[2][1]"; break;
+ case TYPE_FLOAT_MAT3: op << varName << "[0] + " << varName << "[1] + " << varName << "[2]"; break;
+ case TYPE_FLOAT_MAT3X4: op << varName << "[0].xyz + " << varName << "[1].yzw + " << varName << "[2].zwx"; break;
+ case TYPE_FLOAT_MAT4X2: op << varName << "[0][0]+" << varName << "[0][1]+" << varName << "[3][0], " << varName << "[1][0]+" << varName << "[1][1]+" << varName << "[3][1], " << varName << "[2][0]+" << varName << "[2][1]"; break;
+ case TYPE_FLOAT_MAT4X3: op << varName << "[0] + " << varName << "[1] + " << varName << "[2] + " << varName << "[3]"; break;
+ case TYPE_FLOAT_MAT4: op << varName << "[0].xyz+" << varName << "[1].yzw+" << varName << "[2].zwx+" << varName << "[3].wxy"; break;
+
+ default:
+ DE_ASSERT(DE_FALSE);
+ }
+
+ return op.str();
+}
+
+class ShaderMatrixTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderMatrixTests (tcu::TestContext& testCtx);
+ virtual ~ShaderMatrixTests (void);
+
+ virtual void init (void);
+
+private:
+ ShaderMatrixTests (const ShaderMatrixTests&); // not allowed!
+ ShaderMatrixTests& operator= (const ShaderMatrixTests&); // not allowed!
+};
+
+ShaderMatrixTests::ShaderMatrixTests (tcu::TestContext& testCtx)
+ : TestCaseGroup(testCtx, "matrix", "Matrix Tests")
+{
+}
+
+ShaderMatrixTests::~ShaderMatrixTests (void)
+{
+}
+
+void ShaderMatrixTests::init (void)
+{
+ static const struct
+ {
+ const char* name;
+ const char* desc;
+ const MatrixOp op;
+ const bool extendedInputTypeCases; // !< test with const and uniform types too
+ const bool createInputTypeGroup; // !< create group for input types
+ } ops[] =
+ {
+ { "add", "Matrix addition tests", OP_ADD, true, true },
+ { "sub", "Matrix subtraction tests", OP_SUB, true, true },
+ { "mul", "Matrix multiplication tests", OP_MUL, true, true },
+ { "div", "Matrix division tests", OP_DIV, true, true },
+ { "matrixcompmult", "Matrix component-wise multiplication tests", OP_COMP_MUL, false, true },
+ { "outerproduct", "Matrix outerProduct() tests", OP_OUTER_PRODUCT, false, true },
+ { "transpose", "Matrix transpose() tests", OP_TRANSPOSE, false, true },
+ { "determinant", "Matrix determinant() tests", OP_DETERMINANT, false, true },
+ { "inverse", "Matrix inverse() tests", OP_INVERSE, false, true },
+ { "unary_addition", "Matrix unary addition tests", OP_UNARY_PLUS, false, false },
+ { "negation", "Matrix negation tests", OP_NEGATION, false, false },
+ { "pre_increment", "Matrix prefix increment tests", OP_PRE_INCREMENT, false, false },
+ { "pre_decrement", "Matrix prefix decrement tests", OP_PRE_DECREMENT, false, false },
+ { "post_increment", "Matrix postfix increment tests", OP_POST_INCREMENT, false, false },
+ { "post_decrement", "Matrix postfix decrement tests", OP_POST_DECREMENT, false, false },
+ { "add_assign", "Matrix add into tests", OP_ADD_INTO, false, false },
+ { "sub_assign", "Matrix subtract from tests", OP_SUBTRACT_FROM, false, false },
+ { "mul_assign", "Matrix multiply into tests", OP_MULTIPLY_INTO, false, false },
+ { "div_assign", "Matrix divide into tests", OP_DIVIDE_INTO, false, false },
+ };
+
+ struct InputTypeSpec
+ {
+ const char* name;
+ const char* desc;
+ const InputType type;
+ };
+ static const InputTypeSpec extendedInputTypes[] =
+ {
+ { "const", "Constant matrix input", INPUTTYPE_CONST },
+ { "uniform", "Uniform matrix input", INPUTTYPE_UNIFORM },
+ { "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC }
+ };
+ static const InputTypeSpec reducedInputTypes[] =
+ {
+ { "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC }
+ };
+
+ static const DataType matrixTypes[] =
+ {
+ TYPE_FLOAT_MAT2,
+ TYPE_FLOAT_MAT2X3,
+ TYPE_FLOAT_MAT2X4,
+ TYPE_FLOAT_MAT3X2,
+ TYPE_FLOAT_MAT3,
+ TYPE_FLOAT_MAT3X4,
+ TYPE_FLOAT_MAT4X2,
+ TYPE_FLOAT_MAT4X3,
+ TYPE_FLOAT_MAT4
+ };
+
+ static const Precision precisions[] =
+ {
+ PRECISION_LOWP,
+ PRECISION_MEDIUMP,
+ PRECISION_HIGHP
+ };
+
+ for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
+ {
+ const InputTypeSpec* inTypeList = (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
+ const int inTypeListSize = (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) : (DE_LENGTH_OF_ARRAY(reducedInputTypes));
+ const MatrixOp op = ops[opNdx].op;
+ tcu::TestCaseGroup* opGroup = new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
+
+ addChild(opGroup);
+
+ for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
+ {
+ const InputType inputType = inTypeList[inTypeNdx].type;
+ tcu::TestCaseGroup* inGroup;
+
+ if (ops[opNdx].createInputTypeGroup)
+ {
+ inGroup = new tcu::TestCaseGroup(m_testCtx, inTypeList[inTypeNdx].name, inTypeList[inTypeNdx].desc);
+ opGroup->addChild(inGroup);
+ }
+ else
+ inGroup = opGroup;
+
+ for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
+ {
+ DataType matType = matrixTypes[matTypeNdx];
+ int numCols = getDataTypeMatrixNumColumns(matType);
+ int numRows = getDataTypeMatrixNumRows(matType);
+ const char* matTypeName = getDataTypeName(matType);
+
+ for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
+ {
+ Precision precision = precisions[precNdx];
+ const char* precName = getPrecisionName(precision);
+ string baseName = string(precName) + "_" + matTypeName + "_";
+ ShaderInput matIn (inputType, matType, precision);
+
+ if (isOperationMatrixScalar(op))
+ {
+ // Matrix-scalar \note For div cases we use uniform input.
+ ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT, precision);
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_vertex").c_str(), "Matrix-scalar case", matIn, scalarIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_fragment").c_str(), "Matrix-scalar case", matIn, scalarIn, op, false));
+ }
+
+ if (isOperationMatrixVector(op))
+ {
+ // Matrix-vector.
+ DataType colVecType = getDataTypeFloatVec(numCols);
+ ShaderInput colVecIn (op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, colVecType, precision);
+
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + getDataTypeName(colVecType) + "_vertex").c_str(), "Matrix-vector case", matIn, colVecIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + getDataTypeName(colVecType) + "_fragment").c_str(), "Matrix-vector case", matIn, colVecIn, op, false));
+
+ // Vector-matrix.
+ DataType rowVecType = getDataTypeFloatVec(numRows);
+ ShaderInput rowVecIn (op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, rowVecType, precision);
+ string vecMatName = string(precName) + "_" + getDataTypeName(rowVecType) + "_" + matTypeName;
+
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (vecMatName + "_vertex").c_str(), "Vector-matrix case", rowVecIn, matIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (vecMatName + "_fragment").c_str(), "Vector-matrix case", rowVecIn, matIn, op, false));
+ }
+
+ if (isOperationArithmeticMatrixMatrix(op))
+ {
+ // Arithmetic matrix-matrix multiplication.
+ for (int otherCols = 2; otherCols <= 4; otherCols++)
+ {
+ ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, getDataTypeMatrix(otherCols, numCols /* rows */), precision);
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + getDataTypeName(otherMatIn.dataType) + "_vertex").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + getDataTypeName(otherMatIn.dataType) + "_fragment").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, false));
+ }
+ }
+ else if (isOperationComponentwiseMatrixMatrix(op))
+ {
+ // Component-wise.
+ ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + matTypeName + "_vertex").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + matTypeName + "_fragment").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, false));
+ }
+
+ if (isOperationVectorVector(op))
+ {
+ ShaderInput vec1In(inputType, getDataTypeFloatVec(numRows), precision);
+ ShaderInput vec2In((inputType == INPUTTYPE_DYNAMIC) ? (INPUTTYPE_UNIFORM) : (inputType), getDataTypeFloatVec(numCols), precision);
+
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_vertex").c_str(), "Vector-vector case", vec1In, vec2In, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_fragment").c_str(), "Vector-vector case", vec1In, vec2In, op, false));
+ }
+
+ if ((isOperationUnaryAnyMatrix(op)) ||
+ (isOperationUnarySymmetricMatrix(op) && numCols == numRows))
+ {
+ ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_vertex").c_str(), "Matrix case", matIn, voidInput, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_fragment").c_str(), "Matrix case", matIn, voidInput, op, false));
+ }
+
+ if ((isOperationAssignmentAnyMatrix(op)) ||
+ (isOperationAssignmentSymmetricMatrix(op) && numCols == numRows))
+ {
+ ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_vertex").c_str(), "Matrix assignment case", matIn, otherMatIn, op, true));
+ inGroup->addChild(new ShaderMatrixCase(m_testCtx, (baseName + "float_fragment").c_str(), "Matrix assignment case", matIn, otherMatIn, op, false));
+ }
+ }
+ }
+ }
+ }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createMatrixTests (tcu::TestContext& testCtx)
+{
+ return new ShaderMatrixTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDERMATRIXTESTS_HPP
+#define _VKTSHADERRENDERMATRIXTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader matrix arithmetic tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createMatrixTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERMATRIXTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader operators tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderOperatorTests.hpp"
+#include "vktShaderRender.hpp"
+#include "tcuVectorUtil.hpp"
+#include "deStringUtil.hpp"
+
+#include <limits>
+
+using namespace tcu;
+using namespace glu;
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+#if defined(abs)
+# undef abs
+#endif
+
+using de::min;
+using de::max;
+using de::clamp;
+
+// \note VS2013 gets confused without these
+using tcu::asinh;
+using tcu::acosh;
+using tcu::atanh;
+using tcu::exp2;
+using tcu::log2;
+using tcu::trunc;
+
+inline bool logicalAnd (bool a, bool b) { return (a && b); }
+inline bool logicalOr (bool a, bool b) { return (a || b); }
+inline bool logicalXor (bool a, bool b) { return (a != b); }
+
+// \note stdlib.h defines div() that is not compatible with the macros.
+template<typename T> inline T div (T a, T b) { return a / b; }
+
+template<typename T> inline T leftShift (T value, int amount) { return value << amount; }
+
+inline deUint32 rightShift (deUint32 value, int amount) { return value >> amount; }
+inline int rightShift (int value, int amount) { return (value >> amount) | (value >= 0 ? 0 : ~(~0U >> amount)); } // \note Arithmetic shift.
+
+template<typename T, int Size> Vector<T, Size> leftShift (const Vector<T, Size>& value, const Vector<int, Size>& amount)
+{
+ Vector<T, Size> result;
+ for (int i = 0; i < Size; i++)
+ result[i] = leftShift(value[i], amount[i]);
+ return result;
+}
+
+template<typename T, int Size> Vector<T, Size> rightShift (const Vector<T, Size>& value, const Vector<int, Size>& amount)
+{
+ Vector<T, Size> result;
+ for (int i = 0; i < Size; i++)
+ result[i] = rightShift(value[i], amount[i]);
+ return result;
+}
+
+template<typename T, int Size> Vector<T, Size> leftShiftVecScalar (const Vector<T, Size>& value, int amount) { return leftShift(value, Vector<int, Size>(amount)); }
+template<typename T, int Size> Vector<T, Size> rightShiftVecScalar (const Vector<T, Size>& value, int amount) { return rightShift(value, Vector<int, Size>(amount)); }
+
+template<typename T, int Size>
+inline Vector<T, Size> minVecScalar (const Vector<T, Size>& v, T s)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = min(v[i], s);
+ return res;
+}
+
+template<typename T, int Size>
+inline Vector<T, Size> maxVecScalar (const Vector<T, Size>& v, T s)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = max(v[i], s);
+ return res;
+}
+
+template<typename T, int Size>
+inline Vector<T, Size> clampVecScalarScalar (const Vector<T, Size>& v, T s0, T s1)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = clamp(v[i], s0, s1);
+ return res;
+}
+
+template<typename T, int Size>
+inline Vector<T, Size> mixVecVecScalar (const Vector<T, Size>& v0, const Vector<T, Size>& v1, T s)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = mix(v0[i], v1[i], s);
+ return res;
+}
+
+template<typename T, int Size>
+inline Vector<T, Size> stepScalarVec (T s, const Vector<T, Size>& v)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = step(s, v[i]);
+ return res;
+}
+
+template<typename T, int Size>
+inline Vector<T, Size> smoothStepScalarScalarVec (T s0, T s1, const Vector<T, Size>& v)
+{
+ Vector<T, Size> res;
+ for (int i = 0; i < Size; i++)
+ res[i] = smoothStep(s0, s1, v[i]);
+ return res;
+}
+
+inline int addOne (int v) { return v + 1; };
+inline int subOne (int v) { return v - 1; };
+inline deUint32 addOne (deUint32 v) { return v + 1; };
+inline deUint32 subOne (deUint32 v) { return v - 1; };
+
+template<int Size> inline Vector<float, Size> addOne (const Vector<float, Size>& v) { return v + 1.0f; };
+template<int Size> inline Vector<float, Size> subOne (const Vector<float, Size>& v) { return v - 1.0f; };
+template<int Size> inline Vector<int, Size> addOne (const Vector<int, Size>& v) { return v + 1; };
+template<int Size> inline Vector<int, Size> subOne (const Vector<int, Size>& v) { return v - 1; };
+template<int Size> inline Vector<deUint32, Size> addOne (const Vector<deUint32, Size>& v) { return v + 1U; };
+template<int Size> inline Vector<deUint32, Size> subOne (const Vector<deUint32, Size>& v) { return (v.asInt() - 1).asUint(); };
+
+template<typename T> inline T selection (bool cond, T a, T b) { return cond ? a : b; };
+
+// Vec-scalar and scalar-vec binary operators.
+
+// \note This one is done separately due to how the overloaded minus operator is implemented for vector-scalar operands.
+template<int Size> inline Vector<deUint32, Size> subVecScalar (const Vector<deUint32, Size>& v, deUint32 s) { return (v.asInt() - (int)s).asUint(); };
+
+template<typename T, int Size> inline Vector<T, Size> addVecScalar (const Vector<T, Size>& v, T s) { return v + s; };
+template<typename T, int Size> inline Vector<T, Size> subVecScalar (const Vector<T, Size>& v, T s) { return v - s; };
+template<typename T, int Size> inline Vector<T, Size> mulVecScalar (const Vector<T, Size>& v, T s) { return v * s; };
+template<typename T, int Size> inline Vector<T, Size> divVecScalar (const Vector<T, Size>& v, T s) { return v / s; };
+template<typename T, int Size> inline Vector<T, Size> modVecScalar (const Vector<T, Size>& v, T s) { return mod(v, Vector<T, Size>(s)); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseAndVecScalar (const Vector<T, Size>& v, T s) { return bitwiseAnd(v, Vector<T, Size>(s)); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseOrVecScalar (const Vector<T, Size>& v, T s) { return bitwiseOr(v, Vector<T, Size>(s)); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseXorVecScalar (const Vector<T, Size>& v, T s) { return bitwiseXor(v, Vector<T, Size>(s)); };
+
+template<typename T, int Size> inline Vector<T, Size> addScalarVec (T s, const Vector<T, Size>& v) { return s + v; };
+template<typename T, int Size> inline Vector<T, Size> subScalarVec (T s, const Vector<T, Size>& v) { return s - v; };
+template<typename T, int Size> inline Vector<T, Size> mulScalarVec (T s, const Vector<T, Size>& v) { return s * v; };
+template<typename T, int Size> inline Vector<T, Size> divScalarVec (T s, const Vector<T, Size>& v) { return s / v; };
+template<typename T, int Size> inline Vector<T, Size> modScalarVec (T s, const Vector<T, Size>& v) { return mod(Vector<T, Size>(s), v); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseAndScalarVec (T s, const Vector<T, Size>& v) { return bitwiseAnd(Vector<T, Size>(s), v); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseOrScalarVec (T s, const Vector<T, Size>& v) { return bitwiseOr(Vector<T, Size>(s), v); };
+template<typename T, int Size> inline Vector<T, Size> bitwiseXorScalarVec (T s, const Vector<T, Size>& v) { return bitwiseXor(Vector<T, Size>(s), v); };
+
+// Reference functions for specific sequence operations for the sequence operator tests.
+
+// Reference for expression "in0, in2 + in1, in1 + in0"
+inline Vec4 sequenceNoSideEffCase0 (const Vec4& in0, const Vec4& in1, const Vec4& in2) { DE_UNREF(in2); return in1 + in0; }
+// Reference for expression "in0, in2 + in1, in1 + in0"
+inline deUint32 sequenceNoSideEffCase1 (float in0, deUint32 in1, float in2) { DE_UNREF(in0); DE_UNREF(in2); return in1 + in1; }
+// Reference for expression "in0 && in1, in0, ivec2(vec2(in0) + in2)"
+inline IVec2 sequenceNoSideEffCase2 (bool in0, bool in1, const Vec2& in2) { DE_UNREF(in1); return IVec2((int)((float)in0 + in2.x()), (int)((float)in0 + in2.y())); }
+// Reference for expression "in0 + vec4(in1), in2, in1"
+inline IVec4 sequenceNoSideEffCase3 (const Vec4& in0, const IVec4& in1, const BVec4& in2) { DE_UNREF(in0); DE_UNREF(in2); return in1; }
+// Reference for expression "in0++, in1 = in0 + in2, in2 = in1"
+inline Vec4 sequenceSideEffCase0 (const Vec4& in0, const Vec4& in1, const Vec4& in2) { DE_UNREF(in1); return in0 + 1.0f + in2; }
+// Reference for expression "in1++, in0 = float(in1), in1 = uint(in0 + in2)"
+inline deUint32 sequenceSideEffCase1 (float in0, deUint32 in1, float in2) { DE_UNREF(in0); return (deUint32)(float(in1) + 1.0f + in2); }
+// Reference for expression "in1 = in0, in2++, in2 = in2 + vec2(in1), ivec2(in2)"
+inline IVec2 sequenceSideEffCase2 (bool in0, bool in1, const Vec2& in2) { DE_UNREF(in1); return (in2 + Vec2(1.0f) + Vec2((float)in0)).asInt(); }
+// Reference for expression "in0 = in0 + vec4(in2), in1 = in1 + ivec4(in0), in1++"
+inline IVec4 sequenceSideEffCase3 (const Vec4& in0, const IVec4& in1, const BVec4& in2) { return in1 + (in0 + Vec4((float)in2.x(), (float)in2.y(), (float)in2.z(), (float)in2.w())).asInt(); }
+
+// ShaderEvalFunc-type wrappers for the above functions.
+void evalSequenceNoSideEffCase0 (ShaderEvalContext& ctx) { ctx.color = sequenceNoSideEffCase0 (ctx.in[0].swizzle(1, 2, 3, 0), ctx.in[1].swizzle(3, 2, 1, 0), ctx.in[2].swizzle(0, 3, 2, 1)); }
+void evalSequenceNoSideEffCase1 (ShaderEvalContext& ctx) { ctx.color.x() = (float)sequenceNoSideEffCase1 (ctx.in[0].z(), (deUint32)ctx.in[1].x(), ctx.in[2].y()); }
+void evalSequenceNoSideEffCase2 (ShaderEvalContext& ctx) { ctx.color.yz() = sequenceNoSideEffCase2 (ctx.in[0].z() > 0.0f, ctx.in[1].x() > 0.0f, ctx.in[2].swizzle(2, 1)).asFloat(); }
+void evalSequenceNoSideEffCase3 (ShaderEvalContext& ctx) { ctx.color = sequenceNoSideEffCase3 (ctx.in[0].swizzle(1, 2, 3, 0), ctx.in[1].swizzle(3, 2, 1, 0).asInt(), greaterThan(ctx.in[2].swizzle(0, 3, 2, 1), Vec4(0.0f, 0.0f, 0.0f, 0.0f))).asFloat(); }
+void evalSequenceSideEffCase0 (ShaderEvalContext& ctx) { ctx.color = sequenceSideEffCase0 (ctx.in[0].swizzle(1, 2, 3, 0), ctx.in[1].swizzle(3, 2, 1, 0), ctx.in[2].swizzle(0, 3, 2, 1)); }
+void evalSequenceSideEffCase1 (ShaderEvalContext& ctx) { ctx.color.x() = (float)sequenceSideEffCase1 (ctx.in[0].z(), (deUint32)ctx.in[1].x(), ctx.in[2].y()); }
+void evalSequenceSideEffCase2 (ShaderEvalContext& ctx) { ctx.color.yz() = sequenceSideEffCase2 (ctx.in[0].z() > 0.0f, ctx.in[1].x() > 0.0f, ctx.in[2].swizzle(2, 1)).asFloat(); }
+void evalSequenceSideEffCase3 (ShaderEvalContext& ctx) { ctx.color = sequenceSideEffCase3 (ctx.in[0].swizzle(1, 2, 3, 0), ctx.in[1].swizzle(3, 2, 1, 0).asInt(), greaterThan(ctx.in[2].swizzle(0, 3, 2, 1), Vec4(0.0f, 0.0f, 0.0f, 0.0f))).asFloat(); }
+
+static std::string stringJoin (const std::vector<std::string>& elems, const std::string& delim)
+{
+ std::string result;
+ for (int i = 0; i < (int)elems.size(); i++)
+ result += (i > 0 ? delim : "") + elems[i];
+ return result;
+}
+
+static std::string twoValuedVec4 (const std::string& first, const std::string& second, const BVec4& firstMask)
+{
+ std::vector<std::string> elems(4);
+ for (int i = 0; i < 4; i++)
+ elems[i] = firstMask[i] ? first : second;
+
+ return "vec4(" + stringJoin(elems, ", ") + ")";
+}
+
+enum
+{
+ MAX_INPUTS = 3
+};
+
+enum PrecisionMask
+{
+ PRECMASK_NA = 0, //!< Precision not applicable (booleans)
+ PRECMASK_MEDIUMP = (1<<PRECISION_MEDIUMP),
+ PRECMASK_HIGHP = (1<<PRECISION_HIGHP),
+
+ PRECMASK_ALL = PRECMASK_MEDIUMP | PRECMASK_HIGHP
+};
+
+enum ValueType
+{
+ VALUE_NONE = 0,
+ VALUE_FLOAT = (1<<0), // float scalar
+ VALUE_FLOAT_VEC = (1<<1), // float vector
+ VALUE_FLOAT_GENTYPE = (1<<2), // float scalar/vector
+ VALUE_VEC3 = (1<<3), // vec3 only
+ VALUE_MATRIX = (1<<4), // matrix
+ VALUE_BOOL = (1<<5), // boolean scalar
+ VALUE_BOOL_VEC = (1<<6), // boolean vector
+ VALUE_BOOL_GENTYPE = (1<<7), // boolean scalar/vector
+ VALUE_INT = (1<<8), // int scalar
+ VALUE_INT_VEC = (1<<9), // int vector
+ VALUE_INT_GENTYPE = (1<<10), // int scalar/vector
+ VALUE_UINT = (1<<11), // uint scalar
+ VALUE_UINT_VEC = (1<<12), // uint vector
+ VALUE_UINT_GENTYPE = (1<<13), // uint scalar/vector
+
+ // Shorthands.
+ F = VALUE_FLOAT,
+ FV = VALUE_FLOAT_VEC,
+ GT = VALUE_FLOAT_GENTYPE,
+ V3 = VALUE_VEC3,
+ M = VALUE_MATRIX,
+ B = VALUE_BOOL,
+ BV = VALUE_BOOL_VEC,
+ BGT = VALUE_BOOL_GENTYPE,
+ I = VALUE_INT,
+ IV = VALUE_INT_VEC,
+ IGT = VALUE_INT_GENTYPE,
+ U = VALUE_UINT,
+ UV = VALUE_UINT_VEC,
+ UGT = VALUE_UINT_GENTYPE
+};
+
+static inline bool isScalarType (ValueType type)
+{
+ return type == VALUE_FLOAT || type == VALUE_BOOL || type == VALUE_INT || type == VALUE_UINT;
+}
+
+static inline bool isFloatType (ValueType type)
+{
+ return (type & (VALUE_FLOAT | VALUE_FLOAT_VEC | VALUE_FLOAT_GENTYPE)) != 0;
+}
+
+static inline bool isIntType (ValueType type)
+{
+ return (type & (VALUE_INT | VALUE_INT_VEC | VALUE_INT_GENTYPE)) != 0;
+}
+
+static inline bool isUintType (ValueType type)
+{
+ return (type & (VALUE_UINT | VALUE_UINT_VEC | VALUE_UINT_GENTYPE)) != 0;
+}
+
+static inline bool isBoolType (ValueType type)
+{
+ return (type & (VALUE_BOOL | VALUE_BOOL_VEC | VALUE_BOOL_GENTYPE)) != 0;
+}
+
+struct Value
+{
+ Value (ValueType valueType_, const float rangeMin_, const float rangeMax_)
+ : valueType (valueType_)
+ , rangeMin (rangeMin_)
+ , rangeMax (rangeMax_)
+ {
+ }
+
+ ValueType valueType;
+ float rangeMin;
+ float rangeMax;
+};
+
+enum OperationType
+{
+ FUNCTION = 0,
+ OPERATOR,
+ SIDE_EFFECT_OPERATOR // Test the side-effect (as opposed to the result) of a side-effect operator.
+};
+
+struct BuiltinFuncInfo
+{
+ BuiltinFuncInfo (const char* caseName_,
+ const char* shaderFuncName_,
+ ValueType outValue_,
+ Value input0_, Value input1_,
+ Value input2_,
+ const float resultScale_,
+ const float resultBias_,
+ deUint32 precisionMask_,
+ ShaderEvalFunc evalFuncScalar_,
+ ShaderEvalFunc evalFuncVec2_,
+ ShaderEvalFunc evalFuncVec3_,
+ ShaderEvalFunc evalFuncVec4_,
+ OperationType type_=FUNCTION,
+ bool isUnaryPrefix_=true)
+ : caseName (caseName_)
+ , shaderFuncName (shaderFuncName_)
+ , outValue (outValue_)
+ , input0 (input0_)
+ , input1 (input1_)
+ , input2 (input2_)
+ , resultScale (resultScale_)
+ , resultBias (resultBias_)
+ , referenceScale (resultScale_)
+ , referenceBias (resultBias_)
+ , precisionMask (precisionMask_)
+ , evalFuncScalar (evalFuncScalar_)
+ , evalFuncVec2 (evalFuncVec2_)
+ , evalFuncVec3 (evalFuncVec3_)
+ , evalFuncVec4 (evalFuncVec4_)
+ , type (type_)
+ , isUnaryPrefix (isUnaryPrefix_)
+ {
+ }
+
+ BuiltinFuncInfo (const char* caseName_,
+ const char* shaderFuncName_,
+ ValueType outValue_,
+ Value input0_,
+ Value input1_,
+ Value input2_,
+ const float resultScale_,
+ const float resultBias_,
+ const float referenceScale_,
+ const float referenceBias_,
+ deUint32 precisionMask_,
+ ShaderEvalFunc evalFuncScalar_,
+ ShaderEvalFunc evalFuncVec2_,
+ ShaderEvalFunc evalFuncVec3_,
+ ShaderEvalFunc evalFuncVec4_,
+ OperationType type_=FUNCTION,
+ bool isUnaryPrefix_=true)
+ : caseName (caseName_)
+ , shaderFuncName (shaderFuncName_)
+ , outValue (outValue_)
+ , input0 (input0_)
+ , input1 (input1_)
+ , input2 (input2_)
+ , resultScale (resultScale_)
+ , resultBias (resultBias_)
+ , referenceScale (referenceScale_)
+ , referenceBias (referenceBias_)
+ , precisionMask (precisionMask_)
+ , evalFuncScalar (evalFuncScalar_)
+ , evalFuncVec2 (evalFuncVec2_)
+ , evalFuncVec3 (evalFuncVec3_)
+ , evalFuncVec4 (evalFuncVec4_)
+ , type (type_)
+ , isUnaryPrefix (isUnaryPrefix_)
+ {
+ }
+
+ const char* caseName; //!< Name of case.
+ const char* shaderFuncName; //!< Name in shading language.
+ ValueType outValue;
+ Value input0;
+ Value input1;
+ Value input2;
+ float resultScale;
+ float resultBias;
+ float referenceScale;
+ float referenceBias;
+ deUint32 precisionMask;
+ ShaderEvalFunc evalFuncScalar;
+ ShaderEvalFunc evalFuncVec2;
+ ShaderEvalFunc evalFuncVec3;
+ ShaderEvalFunc evalFuncVec4;
+ OperationType type;
+ bool isUnaryPrefix; //!< Whether a unary operator is a prefix operator; redundant unless unary.
+};
+
+static inline BuiltinFuncInfo BuiltinOperInfo (const char* caseName_, const char* shaderFuncName_, ValueType outValue_, Value input0_, Value input1_, Value input2_, const float resultScale_, const float resultBias_, deUint32 precisionMask_, ShaderEvalFunc evalFuncScalar_, ShaderEvalFunc evalFuncVec2_, ShaderEvalFunc evalFuncVec3_, ShaderEvalFunc evalFuncVec4_)
+{
+ return BuiltinFuncInfo(caseName_, shaderFuncName_, outValue_, input0_, input1_, input2_, resultScale_, resultBias_, resultScale_, resultBias_, precisionMask_, evalFuncScalar_, evalFuncVec2_, evalFuncVec3_, evalFuncVec4_, OPERATOR);
+}
+
+// For postfix (unary) operators.
+static inline BuiltinFuncInfo BuiltinPostOperInfo (const char* caseName_, const char* shaderFuncName_, ValueType outValue_, Value input0_, Value input1_, Value input2_, const float resultScale_, const float resultBias_, deUint32 precisionMask_, ShaderEvalFunc evalFuncScalar_, ShaderEvalFunc evalFuncVec2_, ShaderEvalFunc evalFuncVec3_, ShaderEvalFunc evalFuncVec4_)
+{
+ return BuiltinFuncInfo(caseName_, shaderFuncName_, outValue_, input0_, input1_, input2_, resultScale_, resultBias_, resultScale_, resultBias_, precisionMask_, evalFuncScalar_, evalFuncVec2_, evalFuncVec3_, evalFuncVec4_, OPERATOR, false);
+}
+
+static inline BuiltinFuncInfo BuiltinSideEffOperInfo (const char* caseName_, const char* shaderFuncName_, ValueType outValue_, Value input0_, Value input1_, Value input2_, const float resultScale_, const float resultBias_, deUint32 precisionMask_, ShaderEvalFunc evalFuncScalar_, ShaderEvalFunc evalFuncVec2_, ShaderEvalFunc evalFuncVec3_, ShaderEvalFunc evalFuncVec4_)
+{
+ return BuiltinFuncInfo(caseName_, shaderFuncName_, outValue_, input0_, input1_, input2_, resultScale_, resultBias_, resultScale_, resultBias_, precisionMask_, evalFuncScalar_, evalFuncVec2_, evalFuncVec3_, evalFuncVec4_, SIDE_EFFECT_OPERATOR);
+}
+
+// For postfix (unary) operators, testing side-effect.
+static inline BuiltinFuncInfo BuiltinPostSideEffOperInfo (const char* caseName_, const char* shaderFuncName_, ValueType outValue_, Value input0_, Value input1_, Value input2_, const float resultScale_, const float resultBias_, deUint32 precisionMask_, ShaderEvalFunc evalFuncScalar_, ShaderEvalFunc evalFuncVec2_, ShaderEvalFunc evalFuncVec3_, ShaderEvalFunc evalFuncVec4_)
+{
+ return BuiltinFuncInfo(caseName_, shaderFuncName_, outValue_, input0_, input1_, input2_, resultScale_, resultBias_, resultScale_, resultBias_, precisionMask_, evalFuncScalar_, evalFuncVec2_, evalFuncVec3_, evalFuncVec4_, SIDE_EFFECT_OPERATOR, false);
+}
+
+// BuiltinFuncGroup
+
+struct BuiltinFuncGroup
+{
+ BuiltinFuncGroup (const char* name_, const char* description_) : name(name_), description(description_) {}
+ BuiltinFuncGroup& operator<< (const BuiltinFuncInfo& info) { funcInfos.push_back(info); return *this; }
+
+ const char* name;
+ const char* description;
+ std::vector<BuiltinFuncInfo> funcInfos;
+};
+
+static const char* s_inSwizzles[MAX_INPUTS][4] =
+{
+ { "z", "wy", "zxy", "yzwx" },
+ { "x", "yx", "yzx", "wzyx" },
+ { "y", "zy", "wyz", "xwzy" }
+};
+
+static const char* s_outSwizzles[] = { "x", "yz", "xyz", "xyzw" };
+
+static const BVec4 s_outSwizzleChannelMasks[] =
+{
+ BVec4(true, false, false, false),
+ BVec4(false, true, true, false),
+ BVec4(true, true, true, false),
+ BVec4(true, true, true, true )
+};
+
+// OperatorShaderEvaluator
+
+class OperatorShaderEvaluator : public ShaderEvaluator
+{
+public:
+ OperatorShaderEvaluator (const ShaderEvalFunc evalFunc, const float scale, const float bias, int resultScalarSize)
+ : m_evalFunc (evalFunc)
+ , m_resultScalarSize (resultScalarSize)
+ , m_evaluatedScale (scale)
+ , m_evaluatedBias (bias)
+ {
+ DE_ASSERT(de::inRange(resultScalarSize, 1, 4));
+ }
+
+ virtual ~OperatorShaderEvaluator (void)
+ {
+ }
+
+ virtual void evaluate (ShaderEvalContext& ctx) const
+ {
+ m_evalFunc(ctx);
+
+ for (int channelNdx = 0; channelNdx < 4; channelNdx++)
+ if (s_outSwizzleChannelMasks[m_resultScalarSize - 1][channelNdx])
+ ctx.color[channelNdx] = ctx.color[channelNdx] * m_evaluatedScale + m_evaluatedBias;
+ }
+
+private:
+ const ShaderEvalFunc m_evalFunc;
+ const int m_resultScalarSize;
+
+ const float m_evaluatedScale;
+ const float m_evaluatedBias;
+};
+
+// Concrete value.
+
+struct ShaderValue
+{
+ ShaderValue (DataType type_, const float rangeMin_, const float rangeMax_)
+ : type (type_)
+ , rangeMin (rangeMin_)
+ , rangeMax (rangeMax_)
+ {
+ }
+
+ ShaderValue (void)
+ : type (TYPE_LAST)
+ , rangeMin (0.0f)
+ , rangeMax (0.0f)
+ {
+ }
+
+ DataType type;
+ float rangeMin;
+ float rangeMax;
+};
+
+struct ShaderDataSpec
+{
+ ShaderDataSpec (void)
+ : resultScale (1.0f)
+ , resultBias (0.0f)
+ , referenceScale (1.0f)
+ , referenceBias (0.0f)
+ , precision (PRECISION_LAST)
+ , output (TYPE_LAST)
+ , numInputs (0)
+ {
+ }
+
+ float resultScale;
+ float resultBias;
+ float referenceScale;
+ float referenceBias;
+ Precision precision;
+ DataType output;
+ int numInputs;
+ ShaderValue inputs[MAX_INPUTS];
+};
+
+// ShaderOperatorInstance
+
+class ShaderOperatorCaseInstance : public ShaderRenderCaseInstance
+{
+public:
+ ShaderOperatorCaseInstance (Context& context,
+ const bool isVertexCase,
+ const ShaderEvaluator& evaluator,
+ const UniformSetup& uniformSetup,
+ const ShaderDataSpec spec);
+ virtual ~ShaderOperatorCaseInstance (void);
+
+private:
+ const ShaderDataSpec m_spec;
+};
+
+ShaderOperatorCaseInstance::ShaderOperatorCaseInstance (Context& context,
+ const bool isVertexCase,
+ const ShaderEvaluator& evaluator,
+ const UniformSetup& uniformSetup,
+ const ShaderDataSpec spec)
+ : ShaderRenderCaseInstance (context, isVertexCase, evaluator, uniformSetup, DE_NULL)
+ , m_spec (spec)
+{
+ // Setup the user attributes.
+ m_userAttribTransforms.resize(m_spec.numInputs);
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ {
+ const ShaderValue& v = m_spec.inputs[inputNdx];
+ DE_ASSERT(v.type != TYPE_LAST);
+
+ const float rangeMin = v.rangeMin;
+ const float rangeMax = v.rangeMax;
+ const float scale = rangeMax - rangeMin;
+ const float minBias = rangeMin;
+ const float maxBias = rangeMax;
+ Mat4 attribMatrix;
+
+ for (int rowNdx = 0; rowNdx < 4; rowNdx++)
+ {
+ Vec4 row;
+
+ switch ((rowNdx + inputNdx) % 4)
+ {
+ case 0: row = Vec4(scale, 0.0f, 0.0f, minBias); break;
+ case 1: row = Vec4(0.0f, scale, 0.0f, minBias); break;
+ case 2: row = Vec4(-scale, 0.0f, 0.0f, maxBias); break;
+ case 3: row = Vec4(0.0f, -scale, 0.0f, maxBias); break;
+ default: DE_ASSERT(false);
+ }
+
+ attribMatrix.setRow(rowNdx, row);
+ }
+
+ m_userAttribTransforms[inputNdx] = attribMatrix;
+
+ const deUint32 location = 4u + inputNdx;
+ switch(inputNdx)
+ {
+ case 0: useAttribute(location, A_IN0); break;
+ case 1: useAttribute(location, A_IN1); break;
+ case 2: useAttribute(location, A_IN2); break;
+ case 3: useAttribute(location, A_IN3); break;
+ default: DE_ASSERT(false);
+ }
+ }
+}
+
+ShaderOperatorCaseInstance::~ShaderOperatorCaseInstance (void)
+{
+}
+
+// ShaderOperatorCase
+
+class ShaderOperatorCase : public ShaderRenderCase
+{
+public:
+ ShaderOperatorCase (tcu::TestContext& testCtx,
+ const char* caseName,
+ const char* description,
+ const bool isVertexCase,
+ const ShaderEvalFunc evalFunc,
+ const std::string& shaderOp,
+ const ShaderDataSpec& spec);
+ virtual ~ShaderOperatorCase (void);
+
+ virtual TestInstance* createInstance (Context& context) const;
+
+protected:
+ void setupShaderData (void);
+
+private:
+ ShaderOperatorCase (const ShaderOperatorCase&); // not allowed!
+ ShaderOperatorCase& operator= (const ShaderOperatorCase&); // not allowed!
+
+ const ShaderDataSpec m_spec;
+ const std::string m_shaderOp;
+};
+
+ShaderOperatorCase::ShaderOperatorCase (tcu::TestContext& testCtx,
+ const char* caseName,
+ const char* description,
+ const bool isVertexCase,
+ const ShaderEvalFunc evalFunc,
+ const std::string& shaderOp,
+ const ShaderDataSpec& spec)
+ : ShaderRenderCase (testCtx,
+ caseName,
+ description,
+ isVertexCase,
+ new OperatorShaderEvaluator(evalFunc, spec.referenceScale, spec.referenceBias, getDataTypeScalarSize(spec.output)),
+ DE_NULL,
+ DE_NULL)
+ , m_spec (spec)
+ , m_shaderOp (shaderOp)
+{
+ setupShaderData();
+}
+
+TestInstance* ShaderOperatorCase::createInstance (Context& context) const
+{
+ DE_ASSERT(m_evaluator != DE_NULL);
+ DE_ASSERT(m_uniformSetup != DE_NULL);
+ return new ShaderOperatorCaseInstance(context, m_isVertexCase, *m_evaluator, *m_uniformSetup, m_spec);
+}
+
+
+void ShaderOperatorCase::setupShaderData (void)
+{
+ const char* precision = m_spec.precision != PRECISION_LAST ? getPrecisionName(m_spec.precision) : DE_NULL;
+ const char* inputPrecision[MAX_INPUTS];
+
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = m_isVertexCase ? vtx : frag;
+
+ std::string header =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n";
+
+ vtx << header;
+ frag << header;
+
+ // Compute precision for inputs.
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ {
+ const bool isBoolVal = de::inRange<int>(m_spec.inputs[inputNdx].type, TYPE_BOOL, TYPE_BOOL_VEC4);
+ const bool isIntVal = de::inRange<int>(m_spec.inputs[inputNdx].type, TYPE_INT, TYPE_INT_VEC4);
+ const bool isUintVal = de::inRange<int>(m_spec.inputs[inputNdx].type, TYPE_UINT, TYPE_UINT_VEC4);
+ // \note Mediump interpolators are used for booleans, and highp for integers.
+ const Precision prec = isBoolVal ? PRECISION_MEDIUMP
+ : isIntVal || isUintVal ? PRECISION_HIGHP
+ : m_spec.precision;
+ inputPrecision[inputNdx] = getPrecisionName(prec);
+ }
+
+ // Attributes.
+ vtx << "layout(location = 0) in highp vec4 a_position;\n";
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ vtx << "layout(location = " << 4 + inputNdx << ") in " << inputPrecision[inputNdx] << " vec4 a_in" << inputNdx << ";\n";
+
+ // Color output.
+ frag << "layout(location = 0) out mediump vec4 o_color;\n";
+
+ if (m_isVertexCase)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 v_color;\n";
+ }
+ else
+ {
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ {
+ vtx << "layout(location = " << inputNdx + 1 << ") out " << inputPrecision[inputNdx] << " vec4 v_in" << inputNdx << ";\n";
+ frag << "layout(location = " << inputNdx + 1 << ") in " << inputPrecision[inputNdx] << " vec4 v_in" << inputNdx << ";\n";
+ }
+ }
+
+ vtx << "\n";
+ vtx << "void main()\n";
+ vtx << "{\n";
+ vtx << " gl_Position = a_position;\n";
+
+ frag << "\n";
+ frag << "void main()\n";
+ frag << "{\n";
+
+ // Expression inputs.
+ const std::string prefix = m_isVertexCase ? "a_" : "v_";
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ {
+ const DataType inType = m_spec.inputs[inputNdx].type;
+ const int inSize = getDataTypeScalarSize(inType);
+ const bool isInt = de::inRange<int>(inType, TYPE_INT, TYPE_INT_VEC4);
+ const bool isUint = de::inRange<int>(inType, TYPE_UINT, TYPE_UINT_VEC4);
+ const bool isBool = de::inRange<int>(inType, TYPE_BOOL, TYPE_BOOL_VEC4);
+ const char* typeName = getDataTypeName(inType);
+ const char* swizzle = s_inSwizzles[inputNdx][inSize - 1];
+
+ op << "\t";
+ if (precision && !isBool) op << precision << " ";
+
+ op << typeName << " in" << inputNdx << " = ";
+
+ if (isBool)
+ {
+ if (inSize == 1) op << "(";
+ else op << "greaterThan(";
+ }
+ else if (isInt || isUint)
+ op << typeName << "(";
+
+ op << prefix << "in" << inputNdx << "." << swizzle;
+
+ if (isBool)
+ {
+ if (inSize == 1) op << " > 0.0)";
+ else op << ", vec" << inSize << "(0.0))";
+ }
+ else if (isInt || isUint)
+ op << ")";
+
+ op << ";\n";
+ }
+
+ // Result variable.
+ {
+ const char* outTypeName = getDataTypeName(m_spec.output);
+ const bool isBoolOut = de::inRange<int>(m_spec.output, TYPE_BOOL, TYPE_BOOL_VEC4);
+
+ op << "\t";
+ if (precision && !isBoolOut) op << precision << " ";
+ op << outTypeName << " res = " << outTypeName << "(0.0);\n\n";
+ }
+
+ // Expression.
+ op << "\t" << m_shaderOp << "\n\n";
+
+ // Convert to color.
+ const bool isResFloatVec = de::inRange<int>(m_spec.output, TYPE_FLOAT, TYPE_FLOAT_VEC4);
+ const int outScalarSize = getDataTypeScalarSize(m_spec.output);
+
+ op << "\thighp vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n";
+ op << "\tcolor." << s_outSwizzles[outScalarSize-1] << " = ";
+
+ if (!isResFloatVec && outScalarSize == 1)
+ op << "float(res)";
+ else if (!isResFloatVec)
+ op << "vec" << outScalarSize << "(res)";
+ else
+ op << "res";
+
+ op << ";\n";
+
+ // Scale & bias.
+ const float resultScale = m_spec.resultScale;
+ const float resultBias = m_spec.resultBias;
+ if ((resultScale != 1.0f) || (resultBias != 0.0f))
+ {
+ op << "\tcolor = color";
+ if (resultScale != 1.0f) op << " * " << twoValuedVec4(de::toString(resultScale), "1.0", s_outSwizzleChannelMasks[outScalarSize - 1]);
+ if (resultBias != 0.0f) op << " + " << twoValuedVec4(de::floatToString(resultBias, 2), "0.0", s_outSwizzleChannelMasks[outScalarSize - 1]);
+ op << ";\n";
+ }
+
+ // ..
+ if (m_isVertexCase)
+ {
+ vtx << " v_color = color;\n";
+ frag << " o_color = v_color;\n";
+ }
+ else
+ {
+ for (int inputNdx = 0; inputNdx < m_spec.numInputs; inputNdx++)
+ vtx << " v_in" << inputNdx << " = a_in" << inputNdx << ";\n";
+ frag << " o_color = color;\n";
+ }
+
+ vtx << "}\n";
+ frag << "}\n";
+
+ m_vertShaderSource = vtx.str();
+ m_fragShaderSource = frag.str();
+}
+
+ShaderOperatorCase::~ShaderOperatorCase (void)
+{
+}
+
+// Vector math functions.
+template<typename T> inline T nop (T f) { return f; }
+
+template <typename T, int Size>
+Vector<T, Size> nop (const Vector<T, Size>& v) { return v; }
+
+#define DECLARE_UNARY_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2)).x(); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0)); }
+
+#define DECLARE_BINARY_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2), c.in[1].swizzle(0)).x(); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0)); }
+
+#define DECLARE_TERNARY_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2), c.in[1].swizzle(0), c.in[2].swizzle(1)).x(); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0), c.in[2].swizzle(2, 1)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0), c.in[2].swizzle(3, 1, 2)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0), c.in[2].swizzle(0, 3, 2, 1)); }
+
+#define DECLARE_UNARY_SCALAR_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2)); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(3, 1)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2, 0, 1)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0)); }
+
+#define DECLARE_BINARY_SCALAR_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2), c.in[1].swizzle(0)); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color.x() = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0)); }
+
+#define DECLARE_BINARY_BOOL_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bool (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z() > 0.0f, c.in[1].x() > 0.0f); }
+
+#define DECLARE_UNARY_BOOL_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bool (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z() > 0.0f); } \
+ void eval_##FUNC_NAME##_bvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f))).asFloat(); }
+
+#define DECLARE_TERNARY_BOOL_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bool (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z() > 0.0f, c.in[1].x() > 0.0f, c.in[2].y() > 0.0f); } \
+ void eval_##FUNC_NAME##_bvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f)), greaterThan(c.in[1].swizzle(1, 0), Vec2(0.0f)), greaterThan(c.in[2].swizzle(2, 1), Vec2(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f)), greaterThan(c.in[1].swizzle(1, 2, 0), Vec3(0.0f)), greaterThan(c.in[2].swizzle(3, 1, 2), Vec3(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f)), greaterThan(c.in[1].swizzle(3, 2, 1, 0), Vec4(0.0f)), greaterThan(c.in[2].swizzle(0, 3, 2, 1), Vec4(0.0f))).asFloat(); }
+
+#define DECLARE_UNARY_INT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_int (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((int)c.in[0].z()); } \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt()).asFloat(); }
+
+#define DECLARE_BINARY_INT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_int (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((int)c.in[0].z(), (int)c.in[1].x()); } \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt(), c.in[1].swizzle(1, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt(), c.in[1].swizzle(1, 2, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt(), c.in[1].swizzle(3, 2, 1, 0).asInt()).asFloat(); }
+
+#define DECLARE_UNARY_UINT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z()); } \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint()).asFloat(); }
+
+#define DECLARE_BINARY_UINT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z(), (deUint32)c.in[1].x()); } \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asUint()).asFloat(); }
+
+#define DECLARE_TERNARY_INT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_int (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((int)c.in[0].z(), (int)c.in[1].x(), (int)c.in[2].y()); } \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt(), c.in[1].swizzle(1, 0).asInt(), c.in[2].swizzle(2, 1).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt(), c.in[1].swizzle(1, 2, 0).asInt(), c.in[2].swizzle(3, 1, 2).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt(), c.in[1].swizzle(3, 2, 1, 0).asInt(), c.in[2].swizzle(0, 3, 2, 1).asInt()).asFloat(); }
+
+#define DECLARE_TERNARY_UINT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z(), (deUint32)c.in[1].x(), (deUint32)c.in[2].y()); } \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asUint(), c.in[2].swizzle(2, 1).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asUint(), c.in[2].swizzle(3, 1, 2).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asUint(), c.in[2].swizzle(0, 3, 2, 1).asUint()).asFloat(); }
+
+#define DECLARE_VEC_FLOAT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].x()); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].x()); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].x()); }
+
+#define DECLARE_VEC_FLOAT_FLOAT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].x(), c.in[2].y()); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].x(), c.in[2].y()); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].x(), c.in[2].y()); }
+
+#define DECLARE_VEC_VEC_FLOAT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0), c.in[2].y()); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0), c.in[2].y()); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0), c.in[2].y()); }
+
+#define DECLARE_FLOAT_FLOAT_VEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].z(), c.in[1].x(), c.in[2].swizzle(2, 1)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].z(), c.in[1].x(), c.in[2].swizzle(3, 1, 2)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].z(), c.in[1].x(), c.in[2].swizzle(0, 3, 2, 1)); }
+
+#define DECLARE_FLOAT_VEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].z(), c.in[1].swizzle(1, 0)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].z(), c.in[1].swizzle(1, 2, 0)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].z(), c.in[1].swizzle(3, 2, 1, 0)); }
+
+#define DECLARE_IVEC_INT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt(), (int)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt(), (int)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt(), (int)c.in[1].x()).asFloat(); }
+
+#define DECLARE_IVEC_INT_INT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt(), (int)c.in[1].x(), (int)c.in[2].y()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt(), (int)c.in[1].x(), (int)c.in[2].y()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt(), (int)c.in[1].x(), (int)c.in[2].y()).asFloat(); }
+
+#define DECLARE_INT_IVEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME((int)c.in[0].z(), c.in[1].swizzle(1, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME((int)c.in[0].z(), c.in[1].swizzle(1, 2, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME((int)c.in[0].z(), c.in[1].swizzle(3, 2, 1, 0).asInt()).asFloat(); }
+
+#define DECLARE_UVEC_UINT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), (deUint32)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), (deUint32)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), (deUint32)c.in[1].x()).asFloat(); }
+
+#define DECLARE_UVEC_UINT_UINT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), (deUint32)c.in[1].x(), (deUint32)c.in[2].y()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), (deUint32)c.in[1].x(), (deUint32)c.in[2].y()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), (deUint32)c.in[1].x(), (deUint32)c.in[2].y()).asFloat(); }
+
+#define DECLARE_UINT_UVEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME((deUint32)c.in[0].z(), c.in[1].swizzle(1, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME((deUint32)c.in[0].z(), c.in[1].swizzle(1, 2, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME((deUint32)c.in[0].z(), c.in[1].swizzle(3, 2, 1, 0).asUint()).asFloat(); }
+
+#define DECLARE_BINARY_INT_VEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asInt(), c.in[1].swizzle(1, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asInt(), c.in[1].swizzle(1, 2, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asInt(), c.in[1].swizzle(3, 2, 1, 0).asInt()).asFloat(); }
+
+#define DECLARE_BINARY_UINT_VEC_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asUint()).asFloat(); }
+
+#define DECLARE_UINT_INT_GENTYPE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z(), (int)c.in[1].x()); } \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asInt()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asInt()).asFloat(); }
+
+#define DECLARE_UVEC_INT_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), (int)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), (int)c.in[1].x()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), (int)c.in[1].x()).asFloat(); }
+
+
+// Operators.
+
+DECLARE_UNARY_GENTYPE_FUNCS(nop)
+DECLARE_UNARY_GENTYPE_FUNCS(negate)
+DECLARE_UNARY_GENTYPE_FUNCS(addOne)
+DECLARE_UNARY_GENTYPE_FUNCS(subOne)
+DECLARE_BINARY_GENTYPE_FUNCS(add)
+DECLARE_BINARY_GENTYPE_FUNCS(sub)
+DECLARE_BINARY_GENTYPE_FUNCS(mul)
+DECLARE_BINARY_GENTYPE_FUNCS(div)
+
+void eval_selection_float (ShaderEvalContext& c) { c.color.x() = selection(c.in[0].z() > 0.0f, c.in[1].x(), c.in[2].y()); }
+void eval_selection_vec2 (ShaderEvalContext& c) { c.color.yz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 0), c.in[2].swizzle(2, 1)); }
+void eval_selection_vec3 (ShaderEvalContext& c) { c.color.xyz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 2, 0), c.in[2].swizzle(3, 1, 2)); }
+void eval_selection_vec4 (ShaderEvalContext& c) { c.color = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(3, 2, 1, 0), c.in[2].swizzle(0, 3, 2, 1)); }
+
+DECLARE_UNARY_INT_GENTYPE_FUNCS(nop)
+DECLARE_UNARY_INT_GENTYPE_FUNCS(negate)
+DECLARE_UNARY_INT_GENTYPE_FUNCS(addOne)
+DECLARE_UNARY_INT_GENTYPE_FUNCS(subOne)
+DECLARE_UNARY_INT_GENTYPE_FUNCS(bitwiseNot)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(add)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(sub)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(mul)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(div)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(mod)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(bitwiseAnd)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(bitwiseOr)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(bitwiseXor)
+
+void eval_leftShift_int (ShaderEvalContext& c) { c.color.x() = (float)leftShift((int)c.in[0].z(), (int)c.in[1].x()); }
+DECLARE_BINARY_INT_VEC_FUNCS(leftShift)
+void eval_rightShift_int (ShaderEvalContext& c) { c.color.x() = (float)rightShift((int)c.in[0].z(), (int)c.in[1].x()); }
+DECLARE_BINARY_INT_VEC_FUNCS(rightShift)
+DECLARE_IVEC_INT_FUNCS(leftShiftVecScalar)
+DECLARE_IVEC_INT_FUNCS(rightShiftVecScalar)
+
+void eval_selection_int (ShaderEvalContext& c) { c.color.x() = (float)selection(c.in[0].z() > 0.0f, (int)c.in[1].x(), (int)c.in[2].y()); }
+void eval_selection_ivec2 (ShaderEvalContext& c) { c.color.yz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 0).asInt(), c.in[2].swizzle(2, 1).asInt()).asFloat(); }
+void eval_selection_ivec3 (ShaderEvalContext& c) { c.color.xyz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 2, 0).asInt(), c.in[2].swizzle(3, 1, 2).asInt()).asFloat(); }
+void eval_selection_ivec4 (ShaderEvalContext& c) { c.color = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(3, 2, 1, 0).asInt(), c.in[2].swizzle(0, 3, 2, 1).asInt()).asFloat(); }
+
+DECLARE_UNARY_UINT_GENTYPE_FUNCS(nop)
+DECLARE_UNARY_UINT_GENTYPE_FUNCS(negate)
+DECLARE_UNARY_UINT_GENTYPE_FUNCS(bitwiseNot)
+DECLARE_UNARY_UINT_GENTYPE_FUNCS(addOne)
+DECLARE_UNARY_UINT_GENTYPE_FUNCS(subOne)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(add)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(sub)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(mul)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(div)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(mod)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(bitwiseAnd)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(bitwiseOr)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(bitwiseXor)
+
+DECLARE_UINT_INT_GENTYPE_FUNCS(leftShift)
+DECLARE_UINT_INT_GENTYPE_FUNCS(rightShift)
+DECLARE_UVEC_INT_FUNCS(leftShiftVecScalar)
+DECLARE_UVEC_INT_FUNCS(rightShiftVecScalar)
+
+void eval_selection_uint (ShaderEvalContext& c) { c.color.x() = (float)selection(c.in[0].z() > 0.0f, (deUint32)c.in[1].x(), (deUint32)c.in[2].y()); }
+void eval_selection_uvec2 (ShaderEvalContext& c) { c.color.yz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 0).asUint(), c.in[2].swizzle(2, 1).asUint()).asFloat(); }
+void eval_selection_uvec3 (ShaderEvalContext& c) { c.color.xyz() = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(1, 2, 0).asUint(), c.in[2].swizzle(3, 1, 2).asUint()).asFloat(); }
+void eval_selection_uvec4 (ShaderEvalContext& c) { c.color = selection(c.in[0].z() > 0.0f, c.in[1].swizzle(3, 2, 1, 0).asUint(), c.in[2].swizzle(0, 3, 2, 1).asUint()).asFloat(); }
+
+DECLARE_UNARY_BOOL_GENTYPE_FUNCS(boolNot)
+DECLARE_BINARY_BOOL_FUNCS(logicalAnd)
+DECLARE_BINARY_BOOL_FUNCS(logicalOr)
+DECLARE_BINARY_BOOL_FUNCS(logicalXor)
+
+void eval_selection_bool (ShaderEvalContext& c) { c.color.x() = (float)selection(c.in[0].z() > 0.0f, c.in[1].x() > 0.0f, c.in[2].y() > 0.0f); }
+void eval_selection_bvec2 (ShaderEvalContext& c) { c.color.yz() = selection(c.in[0].z() > 0.0f, greaterThan(c.in[1].swizzle(1, 0), Vec2(0.0f, 0.0f)), greaterThan(c.in[2].swizzle(2, 1), Vec2(0.0f, 0.0f))).asFloat(); }
+void eval_selection_bvec3 (ShaderEvalContext& c) { c.color.xyz() = selection(c.in[0].z() > 0.0f, greaterThan(c.in[1].swizzle(1, 2, 0), Vec3(0.0f, 0.0f, 0.0f)), greaterThan(c.in[2].swizzle(3, 1, 2), Vec3(0.0f, 0.0f, 0.0f))).asFloat(); }
+void eval_selection_bvec4 (ShaderEvalContext& c) { c.color = selection(c.in[0].z() > 0.0f, greaterThan(c.in[1].swizzle(3, 2, 1, 0), Vec4(0.0f, 0.0f, 0.0f, 0.0f)), greaterThan(c.in[2].swizzle(0, 3, 2, 1), Vec4(0.0f, 0.0f, 0.0f, 0.0f))).asFloat(); }
+
+DECLARE_VEC_FLOAT_FUNCS(addVecScalar)
+DECLARE_VEC_FLOAT_FUNCS(subVecScalar)
+DECLARE_VEC_FLOAT_FUNCS(mulVecScalar)
+DECLARE_VEC_FLOAT_FUNCS(divVecScalar)
+
+DECLARE_FLOAT_VEC_FUNCS(addScalarVec)
+DECLARE_FLOAT_VEC_FUNCS(subScalarVec)
+DECLARE_FLOAT_VEC_FUNCS(mulScalarVec)
+DECLARE_FLOAT_VEC_FUNCS(divScalarVec)
+
+DECLARE_IVEC_INT_FUNCS(addVecScalar)
+DECLARE_IVEC_INT_FUNCS(subVecScalar)
+DECLARE_IVEC_INT_FUNCS(mulVecScalar)
+DECLARE_IVEC_INT_FUNCS(divVecScalar)
+DECLARE_IVEC_INT_FUNCS(modVecScalar)
+DECLARE_IVEC_INT_FUNCS(bitwiseAndVecScalar)
+DECLARE_IVEC_INT_FUNCS(bitwiseOrVecScalar)
+DECLARE_IVEC_INT_FUNCS(bitwiseXorVecScalar)
+
+DECLARE_INT_IVEC_FUNCS(addScalarVec)
+DECLARE_INT_IVEC_FUNCS(subScalarVec)
+DECLARE_INT_IVEC_FUNCS(mulScalarVec)
+DECLARE_INT_IVEC_FUNCS(divScalarVec)
+DECLARE_INT_IVEC_FUNCS(modScalarVec)
+DECLARE_INT_IVEC_FUNCS(bitwiseAndScalarVec)
+DECLARE_INT_IVEC_FUNCS(bitwiseOrScalarVec)
+DECLARE_INT_IVEC_FUNCS(bitwiseXorScalarVec)
+
+DECLARE_UVEC_UINT_FUNCS(addVecScalar)
+DECLARE_UVEC_UINT_FUNCS(subVecScalar)
+DECLARE_UVEC_UINT_FUNCS(mulVecScalar)
+DECLARE_UVEC_UINT_FUNCS(divVecScalar)
+DECLARE_UVEC_UINT_FUNCS(modVecScalar)
+DECLARE_UVEC_UINT_FUNCS(bitwiseAndVecScalar)
+DECLARE_UVEC_UINT_FUNCS(bitwiseOrVecScalar)
+DECLARE_UVEC_UINT_FUNCS(bitwiseXorVecScalar)
+
+DECLARE_UINT_UVEC_FUNCS(addScalarVec)
+DECLARE_UINT_UVEC_FUNCS(subScalarVec)
+DECLARE_UINT_UVEC_FUNCS(mulScalarVec)
+DECLARE_UINT_UVEC_FUNCS(divScalarVec)
+DECLARE_UINT_UVEC_FUNCS(modScalarVec)
+DECLARE_UINT_UVEC_FUNCS(bitwiseAndScalarVec)
+DECLARE_UINT_UVEC_FUNCS(bitwiseOrScalarVec)
+DECLARE_UINT_UVEC_FUNCS(bitwiseXorScalarVec)
+
+// Built-in functions.
+
+DECLARE_UNARY_GENTYPE_FUNCS(radians)
+DECLARE_UNARY_GENTYPE_FUNCS(degrees)
+DECLARE_UNARY_GENTYPE_FUNCS(sin)
+DECLARE_UNARY_GENTYPE_FUNCS(cos)
+DECLARE_UNARY_GENTYPE_FUNCS(tan)
+DECLARE_UNARY_GENTYPE_FUNCS(asin)
+DECLARE_UNARY_GENTYPE_FUNCS(acos)
+DECLARE_UNARY_GENTYPE_FUNCS(atan)
+DECLARE_BINARY_GENTYPE_FUNCS(atan2)
+DECLARE_UNARY_GENTYPE_FUNCS(sinh)
+DECLARE_UNARY_GENTYPE_FUNCS(cosh)
+DECLARE_UNARY_GENTYPE_FUNCS(tanh)
+DECLARE_UNARY_GENTYPE_FUNCS(asinh)
+DECLARE_UNARY_GENTYPE_FUNCS(acosh)
+DECLARE_UNARY_GENTYPE_FUNCS(atanh)
+
+DECLARE_BINARY_GENTYPE_FUNCS(pow)
+DECLARE_UNARY_GENTYPE_FUNCS(exp)
+DECLARE_UNARY_GENTYPE_FUNCS(log)
+DECLARE_UNARY_GENTYPE_FUNCS(exp2)
+DECLARE_UNARY_GENTYPE_FUNCS(log2)
+DECLARE_UNARY_GENTYPE_FUNCS(sqrt)
+DECLARE_UNARY_GENTYPE_FUNCS(inverseSqrt)
+
+DECLARE_UNARY_GENTYPE_FUNCS(abs)
+DECLARE_UNARY_GENTYPE_FUNCS(sign)
+DECLARE_UNARY_GENTYPE_FUNCS(floor)
+DECLARE_UNARY_GENTYPE_FUNCS(trunc)
+DECLARE_UNARY_GENTYPE_FUNCS(roundToEven)
+DECLARE_UNARY_GENTYPE_FUNCS(ceil)
+DECLARE_UNARY_GENTYPE_FUNCS(fract)
+DECLARE_BINARY_GENTYPE_FUNCS(mod)
+DECLARE_VEC_FLOAT_FUNCS(modVecScalar)
+DECLARE_BINARY_GENTYPE_FUNCS(min)
+DECLARE_VEC_FLOAT_FUNCS(minVecScalar)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(min)
+DECLARE_IVEC_INT_FUNCS(minVecScalar)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(min)
+DECLARE_UVEC_UINT_FUNCS(minVecScalar)
+DECLARE_BINARY_GENTYPE_FUNCS(max)
+DECLARE_VEC_FLOAT_FUNCS(maxVecScalar)
+DECLARE_BINARY_INT_GENTYPE_FUNCS(max)
+DECLARE_IVEC_INT_FUNCS(maxVecScalar)
+DECLARE_BINARY_UINT_GENTYPE_FUNCS(max)
+DECLARE_UVEC_UINT_FUNCS(maxVecScalar)
+DECLARE_TERNARY_GENTYPE_FUNCS(clamp)
+DECLARE_VEC_FLOAT_FLOAT_FUNCS(clampVecScalarScalar)
+DECLARE_TERNARY_INT_GENTYPE_FUNCS(clamp)
+DECLARE_IVEC_INT_INT_FUNCS(clampVecScalarScalar)
+DECLARE_TERNARY_UINT_GENTYPE_FUNCS(clamp)
+DECLARE_UVEC_UINT_UINT_FUNCS(clampVecScalarScalar)
+DECLARE_TERNARY_GENTYPE_FUNCS(mix)
+DECLARE_VEC_VEC_FLOAT_FUNCS(mixVecVecScalar)
+DECLARE_BINARY_GENTYPE_FUNCS(step)
+DECLARE_FLOAT_VEC_FUNCS(stepScalarVec)
+DECLARE_TERNARY_GENTYPE_FUNCS(smoothStep)
+DECLARE_FLOAT_FLOAT_VEC_FUNCS(smoothStepScalarScalarVec)
+
+DECLARE_UNARY_SCALAR_GENTYPE_FUNCS(length)
+DECLARE_BINARY_SCALAR_GENTYPE_FUNCS(distance)
+DECLARE_BINARY_SCALAR_GENTYPE_FUNCS(dot)
+void eval_cross_vec3 (ShaderEvalContext& c) { c.color.xyz() = cross(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0)); }
+
+DECLARE_UNARY_GENTYPE_FUNCS(normalize)
+DECLARE_TERNARY_GENTYPE_FUNCS(faceForward)
+DECLARE_BINARY_GENTYPE_FUNCS(reflect)
+
+void eval_refract_float (ShaderEvalContext& c) { c.color.x() = refract(c.in[0].z(), c.in[1].x(), c.in[2].y()); }
+void eval_refract_vec2 (ShaderEvalContext& c) { c.color.yz() = refract(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0), c.in[2].y()); }
+void eval_refract_vec3 (ShaderEvalContext& c) { c.color.xyz() = refract(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0), c.in[2].y()); }
+void eval_refract_vec4 (ShaderEvalContext& c) { c.color = refract(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0), c.in[2].y()); }
+
+// Compare functions.
+
+#define DECLARE_FLOAT_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z(), c.in[1].x()); } \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0)); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0)); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0)); }
+
+#define DECLARE_FLOAT_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_float (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z(), c.in[1].x()); } \
+ DECLARE_FLOAT_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME)
+
+#define DECLARE_FLOAT_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_vec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1), c.in[1].swizzle(1, 0)).asFloat(); } \
+ void eval_##FUNC_NAME##_vec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1), c.in[1].swizzle(1, 2, 0)).asFloat(); } \
+ void eval_##FUNC_NAME##_vec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0), c.in[1].swizzle(3, 2, 1, 0)).asFloat(); }
+
+#define DECLARE_INT_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_int (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(chopToInt(c.in[0].z()), chopToInt(c.in[1].x())); } \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(chopToInt(c.in[0].swizzle(3, 1)), chopToInt(c.in[1].swizzle(1, 0))); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(chopToInt(c.in[0].swizzle(2, 0, 1)), chopToInt(c.in[1].swizzle(1, 2, 0))); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(chopToInt(c.in[0].swizzle(1, 2, 3, 0)), chopToInt(c.in[1].swizzle(3, 2, 1, 0))); }
+
+#define DECLARE_INT_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_int (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(chopToInt(c.in[0].z()), chopToInt(c.in[1].x())); } \
+ DECLARE_INT_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME)
+
+#define DECLARE_INT_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_ivec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(chopToInt(c.in[0].swizzle(3, 1)), chopToInt(c.in[1].swizzle(1, 0))).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(chopToInt(c.in[0].swizzle(2, 0, 1)), chopToInt(c.in[1].swizzle(1, 2, 0))).asFloat(); } \
+ void eval_##FUNC_NAME##_ivec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(chopToInt(c.in[0].swizzle(1, 2, 3, 0)), chopToInt(c.in[1].swizzle(3, 2, 1, 0))).asFloat(); }
+
+#define DECLARE_UINT_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z(), (deUint32)c.in[1].x()); } \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asUint()); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asUint()); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asUint()); }
+
+#define DECLARE_UINT_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(c.in[0].swizzle(3, 1).asUint(), c.in[1].swizzle(1, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(c.in[0].swizzle(2, 0, 1).asUint(), c.in[1].swizzle(1, 2, 0).asUint()).asFloat(); } \
+ void eval_##FUNC_NAME##_uvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(c.in[0].swizzle(1, 2, 3, 0).asUint(), c.in[1].swizzle(3, 2, 1, 0).asUint()).asFloat(); }
+
+#define DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_uint (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME((deUint32)c.in[0].z(), (deUint32)c.in[1].x()); }
+
+#define DECLARE_BOOL_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bool (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z() > 0.0f, c.in[1].x() > 0.0f); } \
+ void eval_##FUNC_NAME##_bvec2 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f)), greaterThan(c.in[1].swizzle(1, 0), Vec2(0.0f))); } \
+ void eval_##FUNC_NAME##_bvec3 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f)), greaterThan(c.in[1].swizzle(1, 2, 0), Vec3(0.0f))); } \
+ void eval_##FUNC_NAME##_bvec4 (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f)), greaterThan(c.in[1].swizzle(3, 2, 1, 0), Vec4(0.0f))); }
+
+#define DECLARE_BOOL_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bool (ShaderEvalContext& c) { c.color.x() = (float)FUNC_NAME(c.in[0].z() > 0.0f, c.in[1].x() > 0.0f); } \
+ DECLARE_BOOL_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME)
+
+#define DECLARE_BOOL_VEC_CWISE_COMPARE_FUNCS(FUNC_NAME) \
+ void eval_##FUNC_NAME##_bvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f)), greaterThan(c.in[1].swizzle(1, 0), Vec2(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f)), greaterThan(c.in[1].swizzle(1, 2, 0), Vec3(0.0f))).asFloat(); } \
+ void eval_##FUNC_NAME##_bvec4 (ShaderEvalContext& c) { c.color = FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f)), greaterThan(c.in[1].swizzle(3, 2, 1, 0), Vec4(0.0f))).asFloat(); }
+
+DECLARE_FLOAT_COMPARE_FUNCS(allEqual)
+DECLARE_FLOAT_COMPARE_FUNCS(anyNotEqual)
+DECLARE_FLOAT_CWISE_COMPARE_FUNCS(lessThan)
+DECLARE_FLOAT_CWISE_COMPARE_FUNCS(lessThanEqual)
+DECLARE_FLOAT_CWISE_COMPARE_FUNCS(greaterThan)
+DECLARE_FLOAT_CWISE_COMPARE_FUNCS(greaterThanEqual)
+DECLARE_FLOAT_VEC_CWISE_COMPARE_FUNCS(equal)
+DECLARE_FLOAT_VEC_CWISE_COMPARE_FUNCS(notEqual)
+
+DECLARE_INT_COMPARE_FUNCS(allEqual)
+DECLARE_INT_COMPARE_FUNCS(anyNotEqual)
+DECLARE_INT_CWISE_COMPARE_FUNCS(lessThan)
+DECLARE_INT_CWISE_COMPARE_FUNCS(lessThanEqual)
+DECLARE_INT_CWISE_COMPARE_FUNCS(greaterThan)
+DECLARE_INT_CWISE_COMPARE_FUNCS(greaterThanEqual)
+DECLARE_INT_VEC_CWISE_COMPARE_FUNCS(equal)
+DECLARE_INT_VEC_CWISE_COMPARE_FUNCS(notEqual)
+
+DECLARE_UINT_COMPARE_FUNCS(allEqual)
+DECLARE_UINT_COMPARE_FUNCS(anyNotEqual)
+DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(lessThan)
+DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(lessThanEqual)
+DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(greaterThan)
+DECLARE_UINT_SCALAR_CWISE_COMPARE_FUNCS(greaterThanEqual)
+
+DECLARE_BOOL_COMPARE_FUNCS(allEqual)
+DECLARE_BOOL_COMPARE_FUNCS(anyNotEqual)
+DECLARE_BOOL_VEC_CWISE_COMPARE_FUNCS(equal)
+DECLARE_BOOL_VEC_CWISE_COMPARE_FUNCS(notEqual)
+
+// Boolean functions.
+
+#define DECLARE_UNARY_SCALAR_BVEC_FUNCS(GLSL_NAME, FUNC_NAME) \
+ void eval_##GLSL_NAME##_bvec2 (ShaderEvalContext& c) { c.color.x() = float(FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f)))); } \
+ void eval_##GLSL_NAME##_bvec3 (ShaderEvalContext& c) { c.color.x() = float(FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f)))); } \
+ void eval_##GLSL_NAME##_bvec4 (ShaderEvalContext& c) { c.color.x() = float(FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f)))); }
+
+#define DECLARE_UNARY_BVEC_BVEC_FUNCS(GLSL_NAME, FUNC_NAME) \
+ void eval_##GLSL_NAME##_bvec2 (ShaderEvalContext& c) { c.color.yz() = FUNC_NAME(greaterThan(c.in[0].swizzle(3, 1), Vec2(0.0f))).asFloat(); } \
+ void eval_##GLSL_NAME##_bvec3 (ShaderEvalContext& c) { c.color.xyz() = FUNC_NAME(greaterThan(c.in[0].swizzle(2, 0, 1), Vec3(0.0f))).asFloat(); } \
+ void eval_##GLSL_NAME##_bvec4 (ShaderEvalContext& c) { c.color.xyzw() = FUNC_NAME(greaterThan(c.in[0].swizzle(1, 2, 3, 0), Vec4(0.0f))).asFloat(); }
+
+DECLARE_UNARY_SCALAR_BVEC_FUNCS(any, boolAny);
+DECLARE_UNARY_SCALAR_BVEC_FUNCS(all, boolAll);
+
+// ShaderOperatorTests.
+
+class ShaderOperatorTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderOperatorTests (tcu::TestContext& context);
+ virtual ~ShaderOperatorTests (void);
+
+ virtual void init (void);
+
+private:
+ ShaderOperatorTests (const ShaderOperatorTests&); // not allowed!
+ ShaderOperatorTests& operator= (const ShaderOperatorTests&); // not allowed!
+};
+
+ShaderOperatorTests::ShaderOperatorTests(tcu::TestContext& testCtx)
+ : TestCaseGroup(testCtx, "operator", "Operator tests.")
+{
+}
+
+ShaderOperatorTests::~ShaderOperatorTests (void)
+{
+}
+
+void ShaderOperatorTests::init (void)
+{
+ #define BOOL_FUNCS(FUNC_NAME) eval_##FUNC_NAME##_bool, DE_NULL, DE_NULL, DE_NULL
+
+ #define FLOAT_VEC_FUNCS(FUNC_NAME) DE_NULL, eval_##FUNC_NAME##_vec2, eval_##FUNC_NAME##_vec3, eval_##FUNC_NAME##_vec4
+ #define INT_VEC_FUNCS(FUNC_NAME) DE_NULL, eval_##FUNC_NAME##_ivec2, eval_##FUNC_NAME##_ivec3, eval_##FUNC_NAME##_ivec4
+ #define UINT_VEC_FUNCS(FUNC_NAME) DE_NULL, eval_##FUNC_NAME##_uvec2, eval_##FUNC_NAME##_uvec3, eval_##FUNC_NAME##_uvec4
+ #define BOOL_VEC_FUNCS(FUNC_NAME) DE_NULL, eval_##FUNC_NAME##_bvec2, eval_##FUNC_NAME##_bvec3, eval_##FUNC_NAME##_bvec4
+
+ #define FLOAT_GENTYPE_FUNCS(FUNC_NAME) eval_##FUNC_NAME##_float, eval_##FUNC_NAME##_vec2, eval_##FUNC_NAME##_vec3, eval_##FUNC_NAME##_vec4
+ #define INT_GENTYPE_FUNCS(FUNC_NAME) eval_##FUNC_NAME##_int, eval_##FUNC_NAME##_ivec2, eval_##FUNC_NAME##_ivec3, eval_##FUNC_NAME##_ivec4
+ #define UINT_GENTYPE_FUNCS(FUNC_NAME) eval_##FUNC_NAME##_uint, eval_##FUNC_NAME##_uvec2, eval_##FUNC_NAME##_uvec3, eval_##FUNC_NAME##_uvec4
+ #define BOOL_GENTYPE_FUNCS(FUNC_NAME) eval_##FUNC_NAME##_bool, eval_##FUNC_NAME##_bvec2, eval_##FUNC_NAME##_bvec3, eval_##FUNC_NAME##_bvec4
+
+ // Shorthands.
+ Value notUsed = Value(VALUE_NONE, 0.0f, 0.0f);
+
+ std::vector<BuiltinFuncGroup> funcInfoGroups;
+
+ // Unary operators.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("unary_operator", "Unary operator tests")
+ << BuiltinOperInfo ("plus", "+", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(nop))
+ << BuiltinOperInfo ("plus", "+", IGT, Value(IGT, -5.0f, 5.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(nop))
+ << BuiltinOperInfo ("plus", "+", UGT, Value(UGT, 0.0f, 2e2f), notUsed, notUsed, 5e-3f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(nop))
+ << BuiltinOperInfo ("minus", "-", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(negate))
+ << BuiltinOperInfo ("minus", "-", IGT, Value(IGT, -5.0f, 5.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(negate))
+ << BuiltinOperInfo ("minus", "-", UGT, Value(UGT, 0.0f, 4e9f), notUsed, notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(negate))
+ << BuiltinOperInfo ("not", "!", B, Value(B, -1.0f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_NA, eval_boolNot_bool, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo ("bitwise_not", "~", IGT, Value(IGT, -1e5f, 1e5f), notUsed, notUsed, 5e-5f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(bitwiseNot))
+ << BuiltinOperInfo ("bitwise_not", "~", UGT, Value(UGT, 0.0f, 2e9f), notUsed, notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(bitwiseNot))
+
+ // Pre/post incr/decr side effect cases.
+ << BuiltinSideEffOperInfo ("pre_increment_effect", "++", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(addOne))
+ << BuiltinSideEffOperInfo ("pre_increment_effect", "++", IGT, Value(IGT, -6.0f, 4.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(addOne))
+ << BuiltinSideEffOperInfo ("pre_increment_effect", "++", UGT, Value(UGT, 0.0f, 9.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(addOne))
+ << BuiltinSideEffOperInfo ("pre_decrement_effect", "--", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 1.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(subOne))
+ << BuiltinSideEffOperInfo ("pre_decrement_effect", "--", IGT, Value(IGT, -4.0f, 6.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(subOne))
+ << BuiltinSideEffOperInfo ("pre_decrement_effect", "--", UGT, Value(UGT, 1.0f, 10.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(subOne))
+ << BuiltinPostSideEffOperInfo ("post_increment_effect", "++", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(addOne))
+ << BuiltinPostSideEffOperInfo ("post_increment_effect", "++", IGT, Value(IGT, -6.0f, 4.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(addOne))
+ << BuiltinPostSideEffOperInfo ("post_increment_effect", "++", UGT, Value(UGT, 0.0f, 9.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(addOne))
+ << BuiltinPostSideEffOperInfo ("post_decrement_effect", "--", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 1.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(subOne))
+ << BuiltinPostSideEffOperInfo ("post_decrement_effect", "--", IGT, Value(IGT, -4.0f, 6.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(subOne))
+ << BuiltinPostSideEffOperInfo ("post_decrement_effect", "--", UGT, Value(UGT, 1.0f, 10.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(subOne))
+
+ // Pre/post incr/decr result cases.
+ << BuiltinOperInfo ("pre_increment_result", "++", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(addOne))
+ << BuiltinOperInfo ("pre_increment_result", "++", IGT, Value(IGT, -6.0f, 4.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(addOne))
+ << BuiltinOperInfo ("pre_increment_result", "++", UGT, Value(UGT, 0.0f, 9.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(addOne))
+ << BuiltinOperInfo ("pre_decrement_result", "--", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 1.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(subOne))
+ << BuiltinOperInfo ("pre_decrement_result", "--", IGT, Value(IGT, -4.0f, 6.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(subOne))
+ << BuiltinOperInfo ("pre_decrement_result", "--", UGT, Value(UGT, 1.0f, 10.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(subOne))
+ << BuiltinPostOperInfo ("post_increment_result", "++", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(nop))
+ << BuiltinPostOperInfo ("post_increment_result", "++", IGT, Value(IGT, -5.0f, 5.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(nop))
+ << BuiltinPostOperInfo ("post_increment_result", "++", UGT, Value(UGT, 0.0f, 9.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(nop))
+ << BuiltinPostOperInfo ("post_decrement_result", "--", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(nop))
+ << BuiltinPostOperInfo ("post_decrement_result", "--", IGT, Value(IGT, -5.0f, 5.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(nop))
+ << BuiltinPostOperInfo ("post_decrement_result", "--", UGT, Value(UGT, 1.0f, 10.0f), notUsed, notUsed, 0.1f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(nop))
+ );
+
+ BuiltinFuncGroup binaryOpGroup("binary_operator", "Binary operator tests");
+
+ // Normal binary operations and their corresponding assignment operations have lots in common; generate both in the following loop.
+
+ for (int binaryOperatorType = 0; binaryOperatorType <= 2; binaryOperatorType++) // 0: normal op test, 1: assignment op side-effect test, 2: assignment op result test
+ {
+ const bool isNormalOp = binaryOperatorType == 0;
+ const bool isAssignEff = binaryOperatorType == 1;
+ const bool isAssignRes = binaryOperatorType == 2;
+
+ DE_ASSERT(isNormalOp || isAssignEff || isAssignRes);
+ DE_UNREF(isAssignRes);
+
+ const char* addName = isNormalOp ? "add" : isAssignEff ? "add_assign_effect" : "add_assign_result";
+ const char* subName = isNormalOp ? "sub" : isAssignEff ? "sub_assign_effect" : "sub_assign_result";
+ const char* mulName = isNormalOp ? "mul" : isAssignEff ? "mul_assign_effect" : "mul_assign_result";
+ const char* divName = isNormalOp ? "div" : isAssignEff ? "div_assign_effect" : "div_assign_result";
+ const char* modName = isNormalOp ? "mod" : isAssignEff ? "mod_assign_effect" : "mod_assign_result";
+ const char* andName = isNormalOp ? "bitwise_and" : isAssignEff ? "bitwise_and_assign_effect" : "bitwise_and_assign_result";
+ const char* orName = isNormalOp ? "bitwise_or" : isAssignEff ? "bitwise_or_assign_effect" : "bitwise_or_assign_result";
+ const char* xorName = isNormalOp ? "bitwise_xor" : isAssignEff ? "bitwise_xor_assign_effect" : "bitwise_xor_assign_result";
+ const char* leftShiftName = isNormalOp ? "left_shift" : isAssignEff ? "left_shift_assign_effect" : "left_shift_assign_result";
+ const char* rightShiftName = isNormalOp ? "right_shift" : isAssignEff ? "right_shift_assign_effect" : "right_shift_assign_result";
+ const char* addOp = isNormalOp ? "+" : "+=";
+ const char* subOp = isNormalOp ? "-" : "-=";
+ const char* mulOp = isNormalOp ? "*" : "*=";
+ const char* divOp = isNormalOp ? "/" : "/=";
+ const char* modOp = isNormalOp ? "%" : "%=";
+ const char* andOp = isNormalOp ? "&" : "&=";
+ const char* orOp = isNormalOp ? "|" : "|=";
+ const char* xorOp = isNormalOp ? "^" : "^=";
+ const char* leftShiftOp = isNormalOp ? "<<" : "<<=";
+ const char* rightShiftOp = isNormalOp ? ">>" : ">>=";
+
+ // Pointer to appropriate OperInfo function.
+ BuiltinFuncInfo (*operInfoFunc)(const char*, const char*, ValueType, Value, Value, Value, const float, const float, deUint32, ShaderEvalFunc, ShaderEvalFunc, ShaderEvalFunc, ShaderEvalFunc) =
+ isAssignEff ? BuiltinSideEffOperInfo : BuiltinOperInfo;
+
+ DE_ASSERT(operInfoFunc != DE_NULL);
+
+ // The following cases will be added for each operator, precision and fundamental type (float, int, uint) combination, where applicable:
+ // gentype <op> gentype
+ // vector <op> scalar
+ // For normal (non-assigning) operators only:
+ // scalar <op> vector
+
+ // The add operator.
+
+ binaryOpGroup
+ << operInfoFunc(addName, addOp, GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(add))
+ << operInfoFunc(addName, addOp, IGT, Value(IGT, -4.0f, 6.0f), Value(IGT, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(add))
+ << operInfoFunc(addName, addOp, IGT, Value(IGT, -2e9f, 2e9f), Value(IGT, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(add))
+ << operInfoFunc(addName, addOp, UGT, Value(UGT, 0.0f, 1e2f), Value(UGT, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(add))
+ << operInfoFunc(addName, addOp, UGT, Value(UGT, 0.0f, 4e9f), Value(UGT, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(add))
+ << operInfoFunc(addName, addOp, FV, Value(FV, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(addVecScalar))
+ << operInfoFunc(addName, addOp, IV, Value(IV, -4.0f, 6.0f), Value(I, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(addVecScalar))
+ << operInfoFunc(addName, addOp, IV, Value(IV, -2e9f, 2e9f), Value(I, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(addVecScalar))
+ << operInfoFunc(addName, addOp, UV, Value(UV, 0.0f, 1e2f), Value(U, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(addVecScalar))
+ << operInfoFunc(addName, addOp, UV, Value(UV, 0.0f, 4e9f), Value(U, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(addVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(addName, addOp, FV, Value(F, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(addScalarVec))
+ << operInfoFunc(addName, addOp, IV, Value(I, -4.0f, 6.0f), Value(IV, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(addScalarVec))
+ << operInfoFunc(addName, addOp, IV, Value(I, -2e9f, 2e9f), Value(IV, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(addScalarVec))
+ << operInfoFunc(addName, addOp, UV, Value(U, 0.0f, 1e2f), Value(UV, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(addScalarVec))
+ << operInfoFunc(addName, addOp, UV, Value(U, 0.0f, 4e9f), Value(UV, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(addScalarVec));
+
+ // The subtract operator.
+
+ binaryOpGroup
+ << operInfoFunc(subName, subOp, GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(sub))
+ << operInfoFunc(subName, subOp, IGT, Value(IGT, -4.0f, 6.0f), Value(IGT, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(sub))
+ << operInfoFunc(subName, subOp, IGT, Value(IGT, -2e9f, 2e9f), Value(IGT, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(sub))
+ << operInfoFunc(subName, subOp, UGT, Value(UGT, 1e2f, 2e2f), Value(UGT, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(sub))
+ << operInfoFunc(subName, subOp, UGT, Value(UGT, .5e9f, 3.7e9f), Value(UGT, 0.0f, 3.9e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(sub))
+ << operInfoFunc(subName, subOp, FV, Value(FV, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(subVecScalar))
+ << operInfoFunc(subName, subOp, IV, Value(IV, -4.0f, 6.0f), Value(I, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(subVecScalar))
+ << operInfoFunc(subName, subOp, IV, Value(IV, -2e9f, 2e9f), Value(I, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(subVecScalar))
+ << operInfoFunc(subName, subOp, UV, Value(UV, 1e2f, 2e2f), Value(U, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(subVecScalar))
+ << operInfoFunc(subName, subOp, UV, Value(UV, 0.0f, 4e9f), Value(U, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(subVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(subName, subOp, FV, Value(F, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(subScalarVec))
+ << operInfoFunc(subName, subOp, IV, Value(I, -4.0f, 6.0f), Value(IV, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(subScalarVec))
+ << operInfoFunc(subName, subOp, IV, Value(I, -2e9f, 2e9f), Value(IV, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(subScalarVec))
+ << operInfoFunc(subName, subOp, UV, Value(U, 1e2f, 2e2f), Value(UV, 0.0f, 1e2f), notUsed, 5e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(subScalarVec))
+ << operInfoFunc(subName, subOp, UV, Value(U, 0.0f, 4e9f), Value(UV, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(subScalarVec));
+
+ // The multiply operator.
+
+ binaryOpGroup
+ << operInfoFunc(mulName, mulOp, GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(mul))
+ << operInfoFunc(mulName, mulOp, IGT, Value(IGT, -4.0f, 6.0f), Value(IGT, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(mul))
+ << operInfoFunc(mulName, mulOp, IGT, Value(IGT, -3e5f, 3e5f), Value(IGT, -3e4f, 3e4f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(mul))
+ << operInfoFunc(mulName, mulOp, UGT, Value(UGT, 0.0f, 16.0f), Value(UGT, 0.0f, 16.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(mul))
+ << operInfoFunc(mulName, mulOp, UGT, Value(UGT, 0.0f, 6e5f), Value(UGT, 0.0f, 6e4f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(mul))
+ << operInfoFunc(mulName, mulOp, FV, Value(FV, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(mulVecScalar))
+ << operInfoFunc(mulName, mulOp, IV, Value(IV, -4.0f, 6.0f), Value(I, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(mulVecScalar))
+ << operInfoFunc(mulName, mulOp, IV, Value(IV, -3e5f, 3e5f), Value(I, -3e4f, 3e4f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(mulVecScalar))
+ << operInfoFunc(mulName, mulOp, UV, Value(UV, 0.0f, 16.0f), Value(U, 0.0f, 16.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(mulVecScalar))
+ << operInfoFunc(mulName, mulOp, UV, Value(UV, 0.0f, 6e5f), Value(U, 0.0f, 6e4f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(mulVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(mulName, mulOp, FV, Value(F, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(mulScalarVec))
+ << operInfoFunc(mulName, mulOp, IV, Value(I, -4.0f, 6.0f), Value(IV, -6.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(mulScalarVec))
+ << operInfoFunc(mulName, mulOp, IV, Value(I, -3e5f, 3e5f), Value(IV, -3e4f, 3e4f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(mulScalarVec))
+ << operInfoFunc(mulName, mulOp, UV, Value(U, 0.0f, 16.0f), Value(UV, 0.0f, 16.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(mulScalarVec))
+ << operInfoFunc(mulName, mulOp, UV, Value(U, 0.0f, 6e5f), Value(UV, 0.0f, 6e4f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(mulScalarVec));
+
+ // The divide operator.
+
+ binaryOpGroup
+ << operInfoFunc(divName, divOp, GT, Value(GT, -1.0f, 1.0f), Value(GT, -2.0f, -0.5f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(div))
+ << operInfoFunc(divName, divOp, IGT, Value(IGT, 24.0f, 24.0f), Value(IGT, -4.0f, -1.0f), notUsed, 0.04f, 1.0f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(div))
+ << operInfoFunc(divName, divOp, IGT, Value(IGT, 40320.0f, 40320.0f), Value(IGT, -8.0f, -1.0f), notUsed, 1e-5f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(div))
+ << operInfoFunc(divName, divOp, UGT, Value(UGT, 0.0f, 24.0f), Value(UGT, 1.0f, 4.0f), notUsed, 0.04f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(div))
+ << operInfoFunc(divName, divOp, UGT, Value(UGT, 0.0f, 40320.0f), Value(UGT, 1.0f, 8.0f), notUsed, 1e-5f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(div))
+ << operInfoFunc(divName, divOp, FV, Value(FV, -1.0f, 1.0f), Value(F, -2.0f, -0.5f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(divVecScalar))
+ << operInfoFunc(divName, divOp, IV, Value(IV, 24.0f, 24.0f), Value(I, -4.0f, -1.0f), notUsed, 0.04f, 1.0f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(divVecScalar))
+ << operInfoFunc(divName, divOp, IV, Value(IV, 40320.0f, 40320.0f), Value(I, -8.0f, -1.0f), notUsed, 1e-5f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(divVecScalar))
+ << operInfoFunc(divName, divOp, UV, Value(UV, 0.0f, 24.0f), Value(U, 1.0f, 4.0f), notUsed, 0.04f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(divVecScalar))
+ << operInfoFunc(divName, divOp, UV, Value(UV, 0.0f, 40320.0f), Value(U, 1.0f, 8.0f), notUsed, 1e-5f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(divVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(divName, divOp, FV, Value(F, -1.0f, 1.0f), Value(FV, -2.0f, -0.5f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(divScalarVec))
+ << operInfoFunc(divName, divOp, IV, Value(I, 24.0f, 24.0f), Value(IV, -4.0f, -1.0f), notUsed, 0.04f, 1.0f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(divScalarVec))
+ << operInfoFunc(divName, divOp, IV, Value(I, 40320.0f, 40320.0f), Value(IV, -8.0f, -1.0f), notUsed, 1e-5f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(divScalarVec))
+ << operInfoFunc(divName, divOp, UV, Value(U, 0.0f, 24.0f), Value(UV, 1.0f, 4.0f), notUsed, 0.04f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(divScalarVec))
+ << operInfoFunc(divName, divOp, UV, Value(U, 0.0f, 40320.0f), Value(UV, 1.0f, 8.0f), notUsed, 1e-5f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(divScalarVec));
+
+ // The modulus operator.
+
+ binaryOpGroup
+ << operInfoFunc(modName, modOp, IGT, Value(IGT, 0.0f, 6.0f), Value(IGT, 1.1f, 6.1f), notUsed, 0.25f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(mod))
+ << operInfoFunc(modName, modOp, IGT, Value(IGT, 0.0f, 14.0f), Value(IGT, 1.1f, 11.1f), notUsed, 0.1f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(mod))
+ << operInfoFunc(modName, modOp, UGT, Value(UGT, 0.0f, 6.0f), Value(UGT, 1.1f, 6.1f), notUsed, 0.25f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(mod))
+ << operInfoFunc(modName, modOp, UGT, Value(UGT, 0.0f, 24.0f), Value(UGT, 1.1f, 11.1f), notUsed, 0.1f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(mod))
+ << operInfoFunc(modName, modOp, IV, Value(IV, 0.0f, 6.0f), Value(I, 1.1f, 6.1f), notUsed, 0.25f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(modVecScalar))
+ << operInfoFunc(modName, modOp, IV, Value(IV, 0.0f, 6.0f), Value(I, 1.1f, 11.1f), notUsed, 0.1f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(modVecScalar))
+ << operInfoFunc(modName, modOp, UV, Value(UV, 0.0f, 6.0f), Value(U, 1.1f, 6.1f), notUsed, 0.25f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(modVecScalar))
+ << operInfoFunc(modName, modOp, UV, Value(UV, 0.0f, 24.0f), Value(U, 1.1f, 11.1f), notUsed, 0.1f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(modVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(modName, modOp, IV, Value(I, 0.0f, 6.0f), Value(IV, 1.1f, 6.1f), notUsed, 0.25f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(modScalarVec))
+ << operInfoFunc(modName, modOp, IV, Value(I, 0.0f, 6.0f), Value(IV, 1.1f, 11.1f), notUsed, 0.1f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(modScalarVec))
+ << operInfoFunc(modName, modOp, UV, Value(U, 0.0f, 6.0f), Value(UV, 1.1f, 6.1f), notUsed, 0.25f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(modScalarVec))
+ << operInfoFunc(modName, modOp, UV, Value(U, 0.0f, 24.0f), Value(UV, 1.1f, 11.1f), notUsed, 0.1f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(modScalarVec));
+
+ // The bitwise and operator.
+
+ binaryOpGroup
+ << operInfoFunc(andName, andOp, IGT, Value(IGT, -16.0f, 16.0f), Value(IGT, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(bitwiseAnd))
+ << operInfoFunc(andName, andOp, IGT, Value(IGT, -2e9f, 2e9f), Value(IGT, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(bitwiseAnd))
+ << operInfoFunc(andName, andOp, UGT, Value(UGT, 0.0f, 32.0f), Value(UGT, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(bitwiseAnd))
+ << operInfoFunc(andName, andOp, UGT, Value(UGT, 0.0f, 4e9f), Value(UGT, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(bitwiseAnd))
+ << operInfoFunc(andName, andOp, IV, Value(IV, -16.0f, 16.0f), Value(I, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseAndVecScalar))
+ << operInfoFunc(andName, andOp, IV, Value(IV, -2e9f, 2e9f), Value(I, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseAndVecScalar))
+ << operInfoFunc(andName, andOp, UV, Value(UV, 0.0f, 32.0f), Value(U, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseAndVecScalar))
+ << operInfoFunc(andName, andOp, UV, Value(UV, 0.0f, 4e9f), Value(U, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseAndVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(andName, andOp, IV, Value(I, -16.0f, 16.0f), Value(IV, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseAndScalarVec))
+ << operInfoFunc(andName, andOp, IV, Value(I, -2e9f, 2e9f), Value(IV, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseAndScalarVec))
+ << operInfoFunc(andName, andOp, UV, Value(U, 0.0f, 32.0f), Value(UV, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseAndScalarVec))
+ << operInfoFunc(andName, andOp, UV, Value(U, 0.0f, 4e9f), Value(UV, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseAndScalarVec));
+
+ // The bitwise or operator.
+
+ binaryOpGroup
+ << operInfoFunc(orName, orOp, IGT, Value(IGT, -16.0f, 16.0f), Value(IGT, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(bitwiseOr))
+ << operInfoFunc(orName, orOp, IGT, Value(IGT, -2e9f, 2e9f), Value(IGT, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(bitwiseOr))
+ << operInfoFunc(orName, orOp, UGT, Value(UGT, 0.0f, 32.0f), Value(UGT, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(bitwiseOr))
+ << operInfoFunc(orName, orOp, UGT, Value(UGT, 0.0f, 4e9f), Value(UGT, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(bitwiseOr))
+ << operInfoFunc(orName, orOp, IV, Value(IV, -16.0f, 16.0f), Value(I, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseOrVecScalar))
+ << operInfoFunc(orName, orOp, IV, Value(IV, -2e9f, 2e9f), Value(I, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseOrVecScalar))
+ << operInfoFunc(orName, orOp, UV, Value(UV, 0.0f, 32.0f), Value(U, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseOrVecScalar))
+ << operInfoFunc(orName, orOp, UV, Value(UV, 0.0f, 4e9f), Value(U, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseOrVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(orName, orOp, IV, Value(I, -16.0f, 16.0f), Value(IV, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseOrScalarVec))
+ << operInfoFunc(orName, orOp, IV, Value(I, -2e9f, 2e9f), Value(IV, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseOrScalarVec))
+ << operInfoFunc(orName, orOp, UV, Value(U, 0.0f, 32.0f), Value(UV, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseOrScalarVec))
+ << operInfoFunc(orName, orOp, UV, Value(U, 0.0f, 4e9f), Value(UV, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseOrScalarVec));
+
+ // The bitwise xor operator.
+
+ binaryOpGroup
+ << operInfoFunc(xorName, xorOp, IGT, Value(IGT, -16.0f, 16.0f), Value(IGT, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(bitwiseXor))
+ << operInfoFunc(xorName, xorOp, IGT, Value(IGT, -2e9f, 2e9f), Value(IGT, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(bitwiseXor))
+ << operInfoFunc(xorName, xorOp, UGT, Value(UGT, 0.0f, 32.0f), Value(UGT, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(bitwiseXor))
+ << operInfoFunc(xorName, xorOp, UGT, Value(UGT, 0.0f, 4e9f), Value(UGT, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(bitwiseXor))
+ << operInfoFunc(xorName, xorOp, IV, Value(IV, -16.0f, 16.0f), Value(I, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseXorVecScalar))
+ << operInfoFunc(xorName, xorOp, IV, Value(IV, -2e9f, 2e9f), Value(I, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseXorVecScalar))
+ << operInfoFunc(xorName, xorOp, UV, Value(UV, 0.0f, 32.0f), Value(U, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseXorVecScalar))
+ << operInfoFunc(xorName, xorOp, UV, Value(UV, 0.0f, 4e9f), Value(U, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseXorVecScalar));
+
+ if (isNormalOp)
+ binaryOpGroup
+ << operInfoFunc(xorName, xorOp, IV, Value(I, -16.0f, 16.0f), Value(IV, -16.0f, 16.0f), notUsed, 0.03f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(bitwiseXorScalarVec))
+ << operInfoFunc(xorName, xorOp, IV, Value(I, -2e9f, 2e9f), Value(IV, -2e9f, 2e9f), notUsed, 4e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(bitwiseXorScalarVec))
+ << operInfoFunc(xorName, xorOp, UV, Value(U, 0.0f, 32.0f), Value(UV, 0.0f, 32.0f), notUsed, 0.03f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(bitwiseXorScalarVec))
+ << operInfoFunc(xorName, xorOp, UV, Value(U, 0.0f, 4e9f), Value(UV, 0.0f, 4e9f), notUsed, 2e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(bitwiseXorScalarVec));
+
+ // The left shift operator. Second operand (shift amount) can be either int or uint, even for uint and int first operand, respectively.
+
+ for (int isSignedAmount = 0; isSignedAmount <= 1; isSignedAmount++)
+ {
+ ValueType gType = isSignedAmount == 0 ? UGT : IGT;
+ ValueType sType = isSignedAmount == 0 ? U : I;
+ binaryOpGroup
+ << operInfoFunc(leftShiftName, leftShiftOp, IGT, Value(IGT, -7.0f, 7.0f), Value(gType, 0.0f, 4.0f), notUsed, 4e-3f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(leftShift))
+ << operInfoFunc(leftShiftName, leftShiftOp, IGT, Value(IGT, -7.0f, 7.0f), Value(gType, 0.0f, 27.0f), notUsed, 5e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(leftShift))
+ << operInfoFunc(leftShiftName, leftShiftOp, UGT, Value(UGT, 0.0f, 7.0f), Value(gType, 0.0f, 5.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(leftShift))
+ << operInfoFunc(leftShiftName, leftShiftOp, UGT, Value(UGT, 0.0f, 7.0f), Value(gType, 0.0f, 28.0f), notUsed, 5e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(leftShift))
+ << operInfoFunc(leftShiftName, leftShiftOp, IV, Value(IV, -7.0f, 7.0f), Value(sType, 0.0f, 4.0f), notUsed, 4e-3f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(leftShiftVecScalar))
+ << operInfoFunc(leftShiftName, leftShiftOp, IV, Value(IV, -7.0f, 7.0f), Value(sType, 0.0f, 27.0f), notUsed, 5e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(leftShiftVecScalar))
+ << operInfoFunc(leftShiftName, leftShiftOp, UV, Value(UV, 0.0f, 7.0f), Value(sType, 0.0f, 5.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(leftShiftVecScalar))
+ << operInfoFunc(leftShiftName, leftShiftOp, UV, Value(UV, 0.0f, 7.0f), Value(sType, 0.0f, 28.0f), notUsed, 5e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(leftShiftVecScalar));
+ }
+
+ // The right shift operator. Second operand (shift amount) can be either int or uint, even for uint and int first operand, respectively.
+
+ for (int isSignedAmount = 0; isSignedAmount <= 1; isSignedAmount++)
+ {
+ ValueType gType = isSignedAmount == 0 ? UGT : IGT;
+ ValueType sType = isSignedAmount == 0 ? U : I;
+ binaryOpGroup
+ << operInfoFunc(rightShiftName, rightShiftOp, IGT, Value(IGT, -127.0f, 127.0f), Value(gType, 0.0f, 8.0f), notUsed, 4e-3f, 0.5f, PRECMASK_MEDIUMP, INT_GENTYPE_FUNCS(rightShift))
+ << operInfoFunc(rightShiftName, rightShiftOp, IGT, Value(IGT, -2e9f, 2e9f), Value(gType, 0.0f, 31.0f), notUsed, 5e-10f, 0.5f, PRECMASK_HIGHP, INT_GENTYPE_FUNCS(rightShift))
+ << operInfoFunc(rightShiftName, rightShiftOp, UGT, Value(UGT, 0.0f, 255.0f), Value(gType, 0.0f, 8.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_GENTYPE_FUNCS(rightShift))
+ << operInfoFunc(rightShiftName, rightShiftOp, UGT, Value(UGT, 0.0f, 4e9f), Value(gType, 0.0f, 31.0f), notUsed, 5e-10f, 0.0f, PRECMASK_HIGHP, UINT_GENTYPE_FUNCS(rightShift))
+ << operInfoFunc(rightShiftName, rightShiftOp, IV, Value(IV, -127.0f, 127.0f), Value(sType, 0.0f, 8.0f), notUsed, 4e-3f, 0.5f, PRECMASK_MEDIUMP, INT_VEC_FUNCS(rightShiftVecScalar))
+ << operInfoFunc(rightShiftName, rightShiftOp, IV, Value(IV, -2e9f, 2e9f), Value(sType, 0.0f, 31.0f), notUsed, 5e-10f, 0.5f, PRECMASK_HIGHP, INT_VEC_FUNCS(rightShiftVecScalar))
+ << operInfoFunc(rightShiftName, rightShiftOp, UV, Value(UV, 0.0f, 255.0f), Value(sType, 0.0f, 8.0f), notUsed, 4e-3f, 0.0f, PRECMASK_MEDIUMP, UINT_VEC_FUNCS(rightShiftVecScalar))
+ << operInfoFunc(rightShiftName, rightShiftOp, UV, Value(UV, 0.0f, 4e9f), Value(sType, 0.0f, 31.0f), notUsed, 5e-10f, 0.0f, PRECMASK_HIGHP, UINT_VEC_FUNCS(rightShiftVecScalar));
+ }
+ }
+
+ // Rest of binary operators.
+
+ binaryOpGroup
+ // Scalar relational operators.
+ << BuiltinOperInfo("less", "<", B, Value(F, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThan_float, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("less", "<", B, Value(I, -5.0f, 5.0f), Value(I, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThan_int, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("less", "<", B, Value(U, 0.0f, 16.0f), Value(U, 0.0f, 16.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThan_uint, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("less_or_equal", "<=", B, Value(F, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThanEqual_float, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("less_or_equal", "<=", B, Value(I, -5.0f, 5.0f), Value(I, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThanEqual_int, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("less_or_equal", "<=", B, Value(U, 0.0f, 16.0f), Value(U, 0.0f, 16.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_lessThanEqual_uint, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater", ">", B, Value(F, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThan_float, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater", ">", B, Value(I, -5.0f, 5.0f), Value(I, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThan_int, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater", ">", B, Value(U, 0.0f, 16.0f), Value(U, 0.0f, 16.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThan_uint, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater_or_equal", ">=", B, Value(F, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThanEqual_float, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater_or_equal", ">=", B, Value(I, -5.0f, 5.0f), Value(I, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThanEqual_int, DE_NULL, DE_NULL, DE_NULL)
+ << BuiltinOperInfo("greater_or_equal", ">=", B, Value(U, 0.0f, 16.0f), Value(U, 0.0f, 16.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, eval_greaterThanEqual_uint, DE_NULL, DE_NULL, DE_NULL)
+
+ // Equality comparison operators.
+ << BuiltinOperInfo("equal", "==", B, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(allEqual))
+ << BuiltinOperInfo("equal", "==", B, Value(IGT, -5.5f, 4.7f), Value(IGT, -2.1f, 0.1f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_GENTYPE_FUNCS(allEqual))
+ << BuiltinOperInfo("equal", "==", B, Value(UGT, 0.0f, 8.0f), Value(UGT, 3.5f, 4.5f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(allEqual))
+ << BuiltinOperInfo("equal", "==", B, Value(BGT, -2.1f, 2.1f), Value(BGT, -1.1f, 3.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_GENTYPE_FUNCS(allEqual))
+ << BuiltinOperInfo("not_equal", "!=", B, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(anyNotEqual))
+ << BuiltinOperInfo("not_equal", "!=", B, Value(IGT, -5.5f, 4.7f), Value(IGT, -2.1f, 0.1f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_GENTYPE_FUNCS(anyNotEqual))
+ << BuiltinOperInfo("not_equal", "!=", B, Value(UGT, 0.0f, 8.0f), Value(UGT, 3.5f, 4.5f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(anyNotEqual))
+ << BuiltinOperInfo("not_equal", "!=", B, Value(BGT, -2.1f, 2.1f), Value(BGT, -1.1f, 3.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_GENTYPE_FUNCS(anyNotEqual))
+
+ // Logical operators.
+ << BuiltinOperInfo("logical_and", "&&", B, Value(B, -1.0f, 1.0f), Value(B, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_FUNCS(logicalAnd))
+ << BuiltinOperInfo("logical_or", "||", B, Value(B, -1.0f, 1.0f), Value(B, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_FUNCS(logicalOr))
+ << BuiltinOperInfo("logical_xor", "^^", B, Value(B, -1.0f, 1.0f), Value(B, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_FUNCS(logicalXor));
+
+ funcInfoGroups.push_back(binaryOpGroup);
+
+ // Angle and Trigonometry Functions.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("angle_and_trigonometry", "Angle and trigonometry function tests.")
+ << BuiltinFuncInfo("radians", "radians", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 25.0f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(radians) )
+ << BuiltinFuncInfo("degrees", "degrees", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 0.04f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(degrees) )
+ << BuiltinFuncInfo("sin", "sin", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(sin) )
+ << BuiltinFuncInfo("sin2", "sin", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(sin) )
+ << BuiltinFuncInfo("cos", "cos", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(cos) )
+ << BuiltinFuncInfo("cos2", "cos", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(cos) )
+ << BuiltinFuncInfo("tan", "tan", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(tan) )
+ << BuiltinFuncInfo("tan2", "tan", GT, Value(GT, -1.5f, 5.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(tan) )
+ << BuiltinFuncInfo("asin", "asin", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(asin) )
+ << BuiltinFuncInfo("acos", "acos", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(acos) )
+ << BuiltinFuncInfo("atan", "atan", GT, Value(GT, -4.0f, 4.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_HIGHP, FLOAT_GENTYPE_FUNCS(atan) )
+ << BuiltinFuncInfo("atan2", "atan", GT, Value(GT, -4.0f, 4.0f), Value(GT, 0.5f, 2.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(atan2) )
+ << BuiltinFuncInfo("sinh", "sinh", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(sinh) )
+ << BuiltinFuncInfo("sinh2", "sinh", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(sinh) )
+ << BuiltinFuncInfo("cosh", "cosh", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(cosh) )
+ << BuiltinFuncInfo("cosh2", "cosh", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(cosh) )
+ << BuiltinFuncInfo("tanh", "tanh", GT, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(tanh) )
+ << BuiltinFuncInfo("tanh2", "tanh", GT, Value(GT, -1.5f, 5.5f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_MEDIUMP, FLOAT_GENTYPE_FUNCS(tanh) )
+ << BuiltinFuncInfo("asinh", "asinh", GT, Value(GT, -1.0f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(asinh) )
+ << BuiltinFuncInfo("acosh", "acosh", GT, Value(GT, 1.0f, 2.2f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(acosh) )
+ << BuiltinFuncInfo("atanh", "atanh", GT, Value(GT, -0.99f, 0.99f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(atanh) )
+ );
+
+ // Exponential Functions.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("exponential", "Exponential function tests")
+ << BuiltinFuncInfo("pow", "pow", GT, Value(GT, 0.1f, 8.0f), Value(GT, -4.0f, 2.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(pow) )
+ << BuiltinFuncInfo("exp", "exp", GT, Value(GT, -6.0f, 3.0f), notUsed, notUsed, 0.5f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(exp) )
+ << BuiltinFuncInfo("log", "log", GT, Value(GT, 0.1f, 10.0f), notUsed, notUsed, 0.5f, 0.3f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(log) )
+ << BuiltinFuncInfo("exp2", "exp2", GT, Value(GT, -7.0f, 2.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(exp2) )
+ << BuiltinFuncInfo("log2", "log2", GT, Value(GT, 0.1f, 10.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(log2) )
+ << BuiltinFuncInfo("sqrt", "sqrt", GT, Value(GT, 0.0f, 10.0f), notUsed, notUsed, 0.3f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(sqrt) )
+ << BuiltinFuncInfo("inversesqrt", "inversesqrt", GT, Value(GT, 0.5f, 10.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(inverseSqrt) )
+ );
+
+ // Common Functions.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("common_functions", "Common function tests.")
+ << BuiltinFuncInfo("abs", "abs", GT, Value(GT, -2.0f, 2.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(abs) )
+ << BuiltinFuncInfo("sign", "sign", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.3f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(sign) )
+ << BuiltinFuncInfo("floor", "floor", GT, Value(GT, -2.5f, 2.5f), notUsed, notUsed, 0.2f, 0.7f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(floor) )
+ << BuiltinFuncInfo("trunc", "trunc", GT, Value(GT, -2.5f, 2.5f), notUsed, notUsed, 0.2f, 0.7f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(trunc) )
+ << BuiltinFuncInfo("round", "round", GT, Value(GT, -2.5f, 2.5f), notUsed, notUsed, 0.2f, 0.7f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(roundToEven) )
+ << BuiltinFuncInfo("roundEven", "roundEven", GT, Value(GT, -2.5f, 2.5f), notUsed, notUsed, 0.2f, 0.7f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(roundToEven) )
+ << BuiltinFuncInfo("ceil", "ceil", GT, Value(GT, -2.5f, 2.5f), notUsed, notUsed, 0.2f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(ceil) )
+ << BuiltinFuncInfo("fract", "fract", GT, Value(GT, -1.5f, 1.5f), notUsed, notUsed, 0.8f, 0.1f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(fract) )
+ << BuiltinFuncInfo("mod", "mod", GT, Value(GT, -2.0f, 2.0f), Value(GT, 0.9f, 6.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(mod) )
+ << BuiltinFuncInfo("mod", "mod", GT, Value(FV, -2.0f, 2.0f), Value(F, 0.9f, 6.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(modVecScalar) )
+ << BuiltinFuncInfo("min", "min", GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(min) )
+ << BuiltinFuncInfo("min", "min", GT, Value(FV, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(minVecScalar) )
+ << BuiltinFuncInfo("min", "min", IGT,Value(IGT, -4.0f, 4.0f), Value(IGT, -4.0f, 4.0f), notUsed, 0.125f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(min) )
+ << BuiltinFuncInfo("min", "min", IGT,Value(IV, -4.0f, 4.0f), Value(I, -4.0f, 4.0f), notUsed, 0.125f, 0.5f, PRECMASK_ALL, INT_VEC_FUNCS(minVecScalar) )
+ << BuiltinFuncInfo("min", "min", UGT,Value(UGT, 0.0f, 8.0f), Value(UGT, 0.0f, 8.0f), notUsed, 0.125f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(min) )
+ << BuiltinFuncInfo("min", "min", UGT,Value(UV, 0.0f, 8.0f), Value(U, 0.0f, 8.0f), notUsed, 0.125f, 0.0f, PRECMASK_ALL, UINT_VEC_FUNCS(minVecScalar) )
+ << BuiltinFuncInfo("max", "max", GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(max) )
+ << BuiltinFuncInfo("max", "max", GT, Value(FV, -1.0f, 1.0f), Value(F, -1.0f, 1.0f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(maxVecScalar) )
+ << BuiltinFuncInfo("max", "max", IGT,Value(IGT, -4.0f, 4.0f), Value(IGT, -4.0f, 4.0f), notUsed, 0.125f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(max) )
+ << BuiltinFuncInfo("max", "max", IGT,Value(IV, -4.0f, 4.0f), Value(I, -4.0f, 4.0f), notUsed, 0.125f, 0.5f, PRECMASK_ALL, INT_VEC_FUNCS(maxVecScalar) )
+ << BuiltinFuncInfo("max", "max", UGT,Value(UGT, 0.0f, 8.0f), Value(UGT, 0.0f, 8.0f), notUsed, 0.125f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(max) )
+ << BuiltinFuncInfo("max", "max", UGT,Value(UV, 0.0f, 8.0f), Value(U, 0.0f, 8.0f), notUsed, 0.125f, 0.0f, PRECMASK_ALL, UINT_VEC_FUNCS(maxVecScalar) )
+ << BuiltinFuncInfo("clamp", "clamp", GT, Value(GT, -1.0f, 1.0f), Value(GT, -0.5f, 0.5f), Value(GT, 0.5f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(clamp) )
+ << BuiltinFuncInfo("clamp", "clamp", GT, Value(FV, -1.0f, 1.0f), Value(F, -0.5f, 0.5f), Value(F, 0.5f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(clampVecScalarScalar) )
+ << BuiltinFuncInfo("clamp", "clamp", IGT,Value(IGT, -4.0f, 4.0f), Value(IGT, -2.0f, 2.0f), Value(IGT, 2.0f, 4.0f), 0.125f, 0.5f, PRECMASK_ALL, INT_GENTYPE_FUNCS(clamp) )
+ << BuiltinFuncInfo("clamp", "clamp", IGT,Value(IV, -4.0f, 4.0f), Value(I, -2.0f, 2.0f), Value(I, 2.0f, 4.0f), 0.125f, 0.5f, PRECMASK_ALL, INT_VEC_FUNCS(clampVecScalarScalar) )
+ << BuiltinFuncInfo("clamp", "clamp", UGT,Value(UGT, 0.0f, 8.0f), Value(UGT, 2.0f, 6.0f), Value(UGT, 6.0f, 8.0f), 0.125f, 0.0f, PRECMASK_ALL, UINT_GENTYPE_FUNCS(clamp) )
+ << BuiltinFuncInfo("clamp", "clamp", UGT,Value(UV, 0.0f, 8.0f), Value(U, 2.0f, 6.0f), Value(U, 6.0f, 8.0f), 0.125f, 0.0f, PRECMASK_ALL, UINT_VEC_FUNCS(clampVecScalarScalar) )
+ << BuiltinFuncInfo("mix", "mix", GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 1.0f), Value(GT, 0.0f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(mix) )
+ << BuiltinFuncInfo("mix", "mix", GT, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), Value(F, 0.0f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(mixVecVecScalar) )
+ << BuiltinFuncInfo("step", "step", GT, Value(GT, -1.0f, 1.0f), Value(GT, -1.0f, 0.0f), notUsed, 0.5f, 0.25f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(step) )
+ << BuiltinFuncInfo("step", "step", GT, Value(F, -1.0f, 1.0f), Value(FV, -1.0f, 0.0f), notUsed, 0.5f, 0.25f, PRECMASK_ALL, FLOAT_VEC_FUNCS(stepScalarVec) )
+ << BuiltinFuncInfo("smoothstep", "smoothstep", GT, Value(GT, -0.5f, 0.0f), Value(GT, 0.1f, 1.0f), Value(GT, -1.0f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(smoothStep) )
+ << BuiltinFuncInfo("smoothstep", "smoothstep", GT, Value(F, -0.5f, 0.0f), Value(F, 0.1f, 1.0f), Value(FV, -1.0f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_VEC_FUNCS(smoothStepScalarScalarVec) )
+ );
+
+ // Geometric Functions.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("geometric", "Geometric function tests.")
+ << BuiltinFuncInfo("length", "length", F, Value(GT, -5.0f, 5.0f), notUsed, notUsed, 0.1f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(length) )
+ << BuiltinFuncInfo("distance", "distance", F, Value(GT, -5.0f, 5.0f), Value(GT, -5.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(distance) )
+ << BuiltinFuncInfo("dot", "dot", F, Value(GT, -5.0f, 5.0f), Value(GT, -5.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(dot) )
+ << BuiltinFuncInfo("cross", "cross", V3, Value(GT, -5.0f, 5.0f), Value(GT, -5.0f, 5.0f), notUsed, 0.1f, 0.5f, PRECMASK_ALL, DE_NULL, DE_NULL, eval_cross_vec3, DE_NULL )
+ << BuiltinFuncInfo("normalize", "normalize", GT, Value(GT, 0.1f, 4.0f), notUsed, notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(normalize) )
+ << BuiltinFuncInfo("faceforward", "faceforward", GT, Value(GT, -5.0f, 5.0f), Value(GT, -5.0f, 5.0f), Value(GT, -1.0f, 1.0f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(faceForward) )
+ << BuiltinFuncInfo("reflect", "reflect", GT, Value(GT, -0.8f, -0.5f), Value(GT, 0.5f, 0.8f), notUsed, 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(reflect) )
+ << BuiltinFuncInfo("refract", "refract", GT, Value(GT, -0.8f, 1.2f), Value(GT, -1.1f, 0.5f), Value(F, 0.2f, 1.5f), 0.5f, 0.5f, PRECMASK_ALL, FLOAT_GENTYPE_FUNCS(refract) )
+ );
+
+ // Vector Relational Functions.
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("float_compare", "Floating point comparison tests.")
+ << BuiltinFuncInfo("lessThan", "lessThan", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(lessThan) )
+ << BuiltinFuncInfo("lessThanEqual", "lessThanEqual", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(lessThanEqual) )
+ << BuiltinFuncInfo("greaterThan", "greaterThan", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(greaterThan) )
+ << BuiltinFuncInfo("greaterThanEqual", "greaterThanEqual", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(greaterThanEqual) )
+ << BuiltinFuncInfo("equal", "equal", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(equal) )
+ << BuiltinFuncInfo("notEqual", "notEqual", BV, Value(FV, -1.0f, 1.0f), Value(FV, -1.0f, 1.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, FLOAT_VEC_FUNCS(notEqual) )
+ );
+
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("int_compare", "Integer comparison tests.")
+ << BuiltinFuncInfo("lessThan", "lessThan", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(lessThan) )
+ << BuiltinFuncInfo("lessThanEqual", "lessThanEqual", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(lessThanEqual) )
+ << BuiltinFuncInfo("greaterThan", "greaterThan", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(greaterThan) )
+ << BuiltinFuncInfo("greaterThanEqual", "greaterThanEqual", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(greaterThanEqual) )
+ << BuiltinFuncInfo("equal", "equal", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(equal) )
+ << BuiltinFuncInfo("notEqual", "notEqual", BV, Value(IV, -5.2f, 4.9f), Value(IV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_ALL, INT_VEC_FUNCS(notEqual) )
+ );
+
+ funcInfoGroups.push_back(
+ BuiltinFuncGroup("bool_compare", "Boolean comparison tests.")
+ << BuiltinFuncInfo("equal", "equal", BV, Value(BV, -5.2f, 4.9f), Value(BV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_VEC_FUNCS(equal) )
+ << BuiltinFuncInfo("notEqual", "notEqual", BV, Value(BV, -5.2f, 4.9f), Value(BV, -5.0f, 5.0f), notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_VEC_FUNCS(notEqual) )
+ << BuiltinFuncInfo("any", "any", B, Value(BV, -1.0f, 0.3f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_VEC_FUNCS(any) )
+ << BuiltinFuncInfo("all", "all", B, Value(BV, -0.3f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_VEC_FUNCS(all) )
+ << BuiltinFuncInfo("not", "not", BV, Value(BV, -1.0f, 1.0f), notUsed, notUsed, 1.0f, 0.0f, PRECMASK_NA, BOOL_VEC_FUNCS(boolNot) )
+ );
+
+ static const ShaderType s_shaderTypes[] =
+ {
+ SHADERTYPE_VERTEX,
+ SHADERTYPE_FRAGMENT
+ };
+
+ static const DataType s_floatTypes[] =
+ {
+ TYPE_FLOAT,
+ TYPE_FLOAT_VEC2,
+ TYPE_FLOAT_VEC3,
+ TYPE_FLOAT_VEC4
+ };
+
+ static const DataType s_intTypes[] =
+ {
+ TYPE_INT,
+ TYPE_INT_VEC2,
+ TYPE_INT_VEC3,
+ TYPE_INT_VEC4
+ };
+
+ static const DataType s_uintTypes[] =
+ {
+ TYPE_UINT,
+ TYPE_UINT_VEC2,
+ TYPE_UINT_VEC3,
+ TYPE_UINT_VEC4
+ };
+
+ static const DataType s_boolTypes[] =
+ {
+ TYPE_BOOL,
+ TYPE_BOOL_VEC2,
+ TYPE_BOOL_VEC3,
+ TYPE_BOOL_VEC4
+ };
+
+ for (int outerGroupNdx = 0; outerGroupNdx < (int)funcInfoGroups.size(); outerGroupNdx++)
+ {
+ // Create outer group.
+ const BuiltinFuncGroup& outerGroupInfo = funcInfoGroups[outerGroupNdx];
+ TestCaseGroup* outerGroup = new TestCaseGroup(m_testCtx, outerGroupInfo.name, outerGroupInfo.description);
+ addChild(outerGroup);
+
+ // Only create new group if name differs from previous one.
+ TestCaseGroup* innerGroup = DE_NULL;
+
+ for (int funcInfoNdx = 0; funcInfoNdx < (int)outerGroupInfo.funcInfos.size(); funcInfoNdx++)
+ {
+ const BuiltinFuncInfo& funcInfo = outerGroupInfo.funcInfos[funcInfoNdx];
+ const char* shaderFuncName = funcInfo.shaderFuncName;
+ const bool isBoolCase = (funcInfo.precisionMask == PRECMASK_NA);
+ const bool isBoolOut = (funcInfo.outValue & (VALUE_BOOL | VALUE_BOOL_VEC | VALUE_BOOL_GENTYPE)) != 0;
+ const bool isIntOut = (funcInfo.outValue & (VALUE_INT | VALUE_INT_VEC | VALUE_INT_GENTYPE)) != 0;
+ const bool isUintOut = (funcInfo.outValue & (VALUE_UINT | VALUE_UINT_VEC | VALUE_UINT_GENTYPE)) != 0;
+ const bool isFloatOut = !isBoolOut && !isIntOut && !isUintOut;
+
+ if (!innerGroup || (std::string(innerGroup->getName()) != funcInfo.caseName))
+ {
+ std::string groupDesc = std::string("Built-in function ") + shaderFuncName + "() tests.";
+ innerGroup = new TestCaseGroup(m_testCtx, funcInfo.caseName, groupDesc.c_str());
+ outerGroup->addChild(innerGroup);
+ }
+
+ for (int inScalarSize = 1; inScalarSize <= 4; inScalarSize++)
+ {
+ const int outScalarSize = ((funcInfo.outValue == VALUE_FLOAT) || (funcInfo.outValue == VALUE_BOOL)) ? 1 : inScalarSize;
+ const DataType outDataType = isFloatOut ? s_floatTypes[outScalarSize - 1]
+ : isIntOut ? s_intTypes[outScalarSize - 1]
+ : isUintOut ? s_uintTypes[outScalarSize - 1]
+ : isBoolOut ? s_boolTypes[outScalarSize - 1]
+ : TYPE_LAST;
+
+ ShaderEvalFunc evalFunc = DE_NULL;
+ if (inScalarSize == 1) evalFunc = funcInfo.evalFuncScalar;
+ else if (inScalarSize == 2) evalFunc = funcInfo.evalFuncVec2;
+ else if (inScalarSize == 3) evalFunc = funcInfo.evalFuncVec3;
+ else if (inScalarSize == 4) evalFunc = funcInfo.evalFuncVec4;
+ else DE_ASSERT(false);
+
+ // Skip if no valid eval func.
+ if (evalFunc == DE_NULL)
+ continue;
+
+ for (int precision = 0; precision < PRECISION_LAST; precision++)
+ {
+ if ((funcInfo.precisionMask & (1<<precision)) ||
+ (funcInfo.precisionMask == PRECMASK_NA && precision == PRECISION_MEDIUMP)) // use mediump interpolators for booleans
+ {
+ const char* precisionStr = getPrecisionName((Precision)precision);
+ const std::string precisionPrefix = isBoolCase ? "" : (std::string(precisionStr) + "_");
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ const ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ const bool isVertexCase = (ShaderType)shaderType == SHADERTYPE_VERTEX;
+ const bool isUnaryOp = (funcInfo.input1.valueType == VALUE_NONE);
+
+ // \note Data type names will be added to description and name in a following loop.
+ std::string desc = std::string("Built-in function ") + shaderFuncName + "(";
+ std::string name = precisionPrefix;
+
+ // Generate shader op.
+ std::string shaderOp = std::string("res = ");
+
+ // Setup shader data info.
+ ShaderDataSpec shaderSpec;
+ shaderSpec.numInputs = 0;
+ shaderSpec.precision = isBoolCase ? PRECISION_LAST : (Precision)precision;
+ shaderSpec.output = outDataType;
+ shaderSpec.resultScale = funcInfo.resultScale;
+ shaderSpec.resultBias = funcInfo.resultBias;
+ shaderSpec.referenceScale = funcInfo.referenceScale;
+ shaderSpec.referenceBias = funcInfo.referenceBias;
+
+ if (funcInfo.type == OPERATOR)
+ {
+ if (isUnaryOp && funcInfo.isUnaryPrefix)
+ shaderOp += shaderFuncName;
+ }
+ else if (funcInfo.type == FUNCTION)
+ shaderOp += std::string(shaderFuncName) + "(";
+ else // SIDE_EFFECT_OPERATOR
+ shaderOp += "in0;\n\t";
+
+ for (int inputNdx = 0; inputNdx < MAX_INPUTS; inputNdx++)
+ {
+ const Value& prevV = (inputNdx == 1) ? funcInfo.input0 : (inputNdx == 2) ? funcInfo.input1 : funcInfo.input2;
+ const Value& v = (inputNdx == 0) ? funcInfo.input0 : (inputNdx == 1) ? funcInfo.input1 : funcInfo.input2;
+
+ if (v.valueType == VALUE_NONE)
+ continue; // Skip unused input.
+
+ const int prevInScalarSize = isScalarType(prevV.valueType) ? 1 : inScalarSize;
+ const DataType prevInDataType = isFloatType(prevV.valueType) ? s_floatTypes[prevInScalarSize - 1]
+ : isIntType(prevV.valueType) ? s_intTypes[prevInScalarSize - 1]
+ : isUintType(prevV.valueType) ? s_uintTypes[prevInScalarSize - 1]
+ : isBoolType(prevV.valueType) ? s_boolTypes[prevInScalarSize - 1]
+ : TYPE_LAST;
+
+ const int curInScalarSize = isScalarType(v.valueType) ? 1 : inScalarSize;
+ const DataType curInDataType = isFloatType(v.valueType) ? s_floatTypes[curInScalarSize - 1]
+ : isIntType(v.valueType) ? s_intTypes[curInScalarSize - 1]
+ : isUintType(v.valueType) ? s_uintTypes[curInScalarSize - 1]
+ : isBoolType(v.valueType) ? s_boolTypes[curInScalarSize - 1]
+ : TYPE_LAST;
+
+ // Write input type(s) to case description and name.
+
+ if (inputNdx > 0)
+ desc += ", ";
+
+ desc += getDataTypeName(curInDataType);
+
+ if (inputNdx == 0 || prevInDataType != curInDataType) // \note Only write input type to case name if different from previous input type (avoid overly long names).
+ name += std::string("") + getDataTypeName(curInDataType) + "_";
+
+ // Generate op input source.
+
+ if (funcInfo.type == OPERATOR || funcInfo.type == FUNCTION)
+ {
+ if (inputNdx != 0)
+ {
+ if (funcInfo.type == OPERATOR && !isUnaryOp)
+ shaderOp += " " + std::string(shaderFuncName) + " ";
+ else
+ shaderOp += ", ";
+ }
+
+ shaderOp += "in" + de::toString(inputNdx);
+
+ if (funcInfo.type == OPERATOR && isUnaryOp && !funcInfo.isUnaryPrefix)
+ shaderOp += std::string(shaderFuncName);
+ }
+ else
+ {
+ DE_ASSERT(funcInfo.type == SIDE_EFFECT_OPERATOR);
+
+ if (inputNdx != 0 || (isUnaryOp && funcInfo.isUnaryPrefix))
+ shaderOp += std::string("") + (isUnaryOp ? "" : " ") + shaderFuncName + (isUnaryOp ? "" : " ");
+
+ shaderOp += inputNdx == 0 ? "res" : "in" + de::toString(inputNdx); // \note in0 has already been assigned to res, so start from in1.
+
+ if (isUnaryOp && !funcInfo.isUnaryPrefix)
+ shaderOp += shaderFuncName;
+ }
+
+ // Fill in shader info.
+ shaderSpec.inputs[shaderSpec.numInputs++] = ShaderValue(curInDataType, v.rangeMin, v.rangeMax);
+ }
+
+ if (funcInfo.type == FUNCTION)
+ shaderOp += ")";
+
+ shaderOp += ";";
+
+ desc += ").";
+ name += shaderTypeName;
+
+ // Create the test case.
+ innerGroup->addChild(new ShaderOperatorCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, evalFunc, shaderOp, shaderSpec));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // The ?: selection operator.
+
+ static const struct
+ {
+ const DataType type; // The type of "Y" and "Z" operands in "X ? Y : Z" (X is always bool).
+ const ShaderEvalFunc evalFunc;
+ } s_selectionInfo[] =
+ {
+ { TYPE_FLOAT, eval_selection_float },
+ { TYPE_FLOAT_VEC2, eval_selection_vec2 },
+ { TYPE_FLOAT_VEC3, eval_selection_vec3 },
+ { TYPE_FLOAT_VEC4, eval_selection_vec4 },
+ { TYPE_INT, eval_selection_int },
+ { TYPE_INT_VEC2, eval_selection_ivec2 },
+ { TYPE_INT_VEC3, eval_selection_ivec3 },
+ { TYPE_INT_VEC4, eval_selection_ivec4 },
+ { TYPE_UINT, eval_selection_uint },
+ { TYPE_UINT_VEC2, eval_selection_uvec2 },
+ { TYPE_UINT_VEC3, eval_selection_uvec3 },
+ { TYPE_UINT_VEC4, eval_selection_uvec4 },
+ { TYPE_BOOL, eval_selection_bool },
+ { TYPE_BOOL_VEC2, eval_selection_bvec2 },
+ { TYPE_BOOL_VEC3, eval_selection_bvec3 },
+ { TYPE_BOOL_VEC4, eval_selection_bvec4 }
+ };
+
+ TestCaseGroup* selectionGroup = new TestCaseGroup(m_testCtx, "selection", "Selection operator tests");
+ addChild(selectionGroup);
+
+ for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_selectionInfo); typeNdx++)
+ {
+ const DataType curType = s_selectionInfo[typeNdx].type;
+ const ShaderEvalFunc evalFunc = s_selectionInfo[typeNdx].evalFunc;
+ const bool isBoolCase = isDataTypeBoolOrBVec(curType);
+ const bool isFloatCase = isDataTypeFloatOrVec(curType);
+ const bool isIntCase = isDataTypeIntOrIVec(curType);
+ const bool isUintCase = isDataTypeUintOrUVec(curType);
+ const char* dataTypeStr = getDataTypeName(curType);
+
+ DE_ASSERT(isBoolCase || isFloatCase || isIntCase || isUintCase);
+ DE_UNREF(isIntCase);
+
+ for (int precision = 0; precision < (int)PRECISION_LAST; precision++)
+ {
+ if (isBoolCase && precision != PRECISION_MEDIUMP) // Use mediump interpolators for booleans.
+ continue;
+
+ const char* precisionStr = getPrecisionName((Precision)precision);
+ std::string precisionPrefix = isBoolCase ? "" : (std::string(precisionStr) + "_");
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ const ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ const bool isVertexCase = (ShaderType)shaderType == SHADERTYPE_VERTEX;
+
+ std::string name = precisionPrefix + dataTypeStr + "_" + shaderTypeName;
+
+ ShaderDataSpec shaderSpec;
+ shaderSpec.numInputs = 3;
+ shaderSpec.precision = isBoolCase ? PRECISION_LAST : (Precision)precision;
+ shaderSpec.output = curType;
+ shaderSpec.resultScale = (isBoolCase ? 1.0f : (isFloatCase ? 0.5f : (isUintCase ? 0.5f : 0.1f)));
+ shaderSpec.resultBias = (isBoolCase ? 0.0f : (isFloatCase ? 0.5f : (isUintCase ? 0.0f : 0.5f)));
+ shaderSpec.referenceScale = shaderSpec.resultScale;
+ shaderSpec.referenceBias = shaderSpec.resultBias;
+
+ const float rangeMin = (isBoolCase ? -1.0f : (isFloatCase ? -1.0f : (isUintCase ? 0.0f : -5.0f)));
+ const float rangeMax = (isBoolCase ? 1.0f : (isFloatCase ? 1.0f : (isUintCase ? 2.0f : 5.0f)));
+
+ shaderSpec.inputs[0] = ShaderValue(TYPE_BOOL, -1.0f, 1.0f);
+ shaderSpec.inputs[1] = ShaderValue(curType, rangeMin, rangeMax);
+ shaderSpec.inputs[2] = ShaderValue(curType, rangeMin, rangeMax);
+
+ selectionGroup->addChild(new ShaderOperatorCase(m_testCtx, name.c_str(), "", isVertexCase, evalFunc, "res = in0 ? in1 : in2;", shaderSpec));
+ }
+ }
+ }
+
+ // The sequence operator (comma).
+
+ TestCaseGroup* sequenceGroup = new TestCaseGroup(m_testCtx, "sequence", "Sequence operator tests");
+ addChild(sequenceGroup);
+
+ TestCaseGroup* sequenceNoSideEffGroup = new TestCaseGroup(m_testCtx, "no_side_effects", "Sequence tests without side-effects");
+ TestCaseGroup* sequenceSideEffGroup = new TestCaseGroup(m_testCtx, "side_effects", "Sequence tests with side-effects");
+ sequenceGroup->addChild(sequenceNoSideEffGroup);
+ sequenceGroup->addChild(sequenceSideEffGroup);
+
+ static const struct
+ {
+ const bool containsSideEffects;
+ const char* caseName;
+ const char* expressionStr;
+ const int numInputs;
+ const DataType inputTypes[MAX_INPUTS];
+ const DataType resultType;
+ const ShaderEvalFunc evalFunc;
+ } s_sequenceCases[] =
+ {
+ { false, "vec4", "in0, in2 + in1, in1 + in0", 3, { TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4 }, TYPE_FLOAT_VEC4, evalSequenceNoSideEffCase0 },
+ { false, "float_uint", "in0 + in2, in1 + in1", 3, { TYPE_FLOAT, TYPE_UINT, TYPE_FLOAT }, TYPE_UINT, evalSequenceNoSideEffCase1 },
+ { false, "bool_vec2", "in0 && in1, in0, ivec2(vec2(in0) + in2)", 3, { TYPE_BOOL, TYPE_BOOL, TYPE_FLOAT_VEC2 }, TYPE_INT_VEC2, evalSequenceNoSideEffCase2 },
+ { false, "vec4_ivec4_bvec4", "in0 + vec4(in1), in2, in1", 3, { TYPE_FLOAT_VEC4, TYPE_INT_VEC4, TYPE_BOOL_VEC4 }, TYPE_INT_VEC4, evalSequenceNoSideEffCase3 },
+
+ { true, "vec4", "in0++, in1 = in0 + in2, in2 = in1", 3, { TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4 }, TYPE_FLOAT_VEC4, evalSequenceSideEffCase0 },
+ { true, "float_uint", "in1++, in0 = float(in1), in1 = uint(in0 + in2)", 3, { TYPE_FLOAT, TYPE_UINT, TYPE_FLOAT }, TYPE_UINT, evalSequenceSideEffCase1 },
+ { true, "bool_vec2", "in1 = in0, in2++, in2 = in2 + vec2(in1), ivec2(in2)", 3, { TYPE_BOOL, TYPE_BOOL, TYPE_FLOAT_VEC2 }, TYPE_INT_VEC2, evalSequenceSideEffCase2 },
+ { true, "vec4_ivec4_bvec4", "in0 = in0 + vec4(in2), in1 = in1 + ivec4(in0), in1++", 3, { TYPE_FLOAT_VEC4, TYPE_INT_VEC4, TYPE_BOOL_VEC4 }, TYPE_INT_VEC4, evalSequenceSideEffCase3 }
+ };
+
+ for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_sequenceCases); caseNdx++)
+ {
+ for (int precision = 0; precision < (int)PRECISION_LAST; precision++)
+ {
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
+ {
+ const ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
+ const char* shaderTypeName = getShaderTypeName(shaderType);
+ const bool isVertexCase = (ShaderType)shaderType == SHADERTYPE_VERTEX;
+
+ std::string name = std::string("") + getPrecisionName((Precision)precision) + "_" + s_sequenceCases[caseNdx].caseName + "_" + shaderTypeName;
+
+ ShaderDataSpec shaderSpec;
+ shaderSpec.numInputs = s_sequenceCases[caseNdx].numInputs;
+ shaderSpec.precision = (Precision)precision;
+ shaderSpec.output = s_sequenceCases[caseNdx].resultType;
+ shaderSpec.resultScale = 0.5f;
+ shaderSpec.resultBias = 0.0f;
+ shaderSpec.referenceScale = shaderSpec.resultScale;
+ shaderSpec.referenceBias = shaderSpec.resultBias;
+
+ for (int inputNdx = 0; inputNdx < s_sequenceCases[caseNdx].numInputs; inputNdx++)
+ {
+ const DataType type = s_sequenceCases[caseNdx].inputTypes[inputNdx];
+ const float rangeMin = (isDataTypeFloatOrVec(type) ? -0.5f : (isDataTypeIntOrIVec(type) ? -2.0f : (isDataTypeUintOrUVec(type) ? 0.0f : -1.0f)));
+ const float rangeMax = (isDataTypeFloatOrVec(type) ? 0.5f : (isDataTypeIntOrIVec(type) ? 2.0f : (isDataTypeUintOrUVec(type) ? 2.0f : 1.0f)));
+
+ shaderSpec.inputs[inputNdx] = ShaderValue(type, rangeMin, rangeMax);
+ }
+
+ const std::string expression = std::string("") + "res = (" + s_sequenceCases[caseNdx].expressionStr + ");";
+
+ TestCaseGroup* group = s_sequenceCases[caseNdx].containsSideEffects ? sequenceSideEffGroup : sequenceNoSideEffGroup;
+ group->addChild(new ShaderOperatorCase(m_testCtx, name.c_str(), "", isVertexCase, s_sequenceCases[caseNdx].evalFunc, expression.c_str(), shaderSpec));
+ }
+ }
+ }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createOperatorTests (tcu::TestContext& testCtx)
+{
+ return new ShaderOperatorTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDEROPERATORTESTS_HPP
+#define _VKTSHADERRENDEROPERATORTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader operators tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createOperatorTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTFSHADERRENDEROPERATORTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader return statement tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderReturnTests.hpp"
+#include "vktShaderRender.hpp"
+#include "tcuStringTemplate.hpp"
+
+#include <map>
+#include <string>
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+enum ReturnMode
+{
+ RETURNMODE_ALWAYS = 0,
+ RETURNMODE_NEVER,
+ RETURNMODE_DYNAMIC,
+
+ RETURNMODE_LAST
+};
+
+// Evaluation functions
+inline void evalReturnAlways (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
+inline void evalReturnNever (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,2,1); }
+inline void evalReturnDynamic (ShaderEvalContext& c) { c.color.xyz() = (c.coords.x()+c.coords.y() >= 0.0f) ? c.coords.swizzle(0,1,2) : c.coords.swizzle(3,2,1); }
+
+static ShaderEvalFunc getEvalFunc (ReturnMode mode)
+{
+ switch (mode)
+ {
+ case RETURNMODE_ALWAYS: return evalReturnAlways;
+ case RETURNMODE_NEVER: return evalReturnNever;
+ case RETURNMODE_DYNAMIC: return evalReturnDynamic;
+ default:
+ DE_ASSERT(DE_FALSE);
+ return (ShaderEvalFunc)DE_NULL;
+ }
+}
+
+class ShaderReturnCase : public ShaderRenderCase
+{
+public:
+ ShaderReturnCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ bool isVertexCase,
+ const std::string& shaderSource,
+ const ShaderEvalFunc evalFunc,
+ const UniformSetup* uniformFunc);
+ virtual ~ShaderReturnCase (void);
+};
+
+ShaderReturnCase::ShaderReturnCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ bool isVertexCase,
+ const std::string& shaderSource,
+ const ShaderEvalFunc evalFunc,
+ const UniformSetup* uniformFunc)
+ : ShaderRenderCase(testCtx, name, description, isVertexCase, evalFunc, uniformFunc, DE_NULL)
+{
+ if (isVertexCase)
+ {
+ m_vertShaderSource = shaderSource;
+ m_fragShaderSource =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_color;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = v_color;\n"
+ "}\n";
+ }
+ else
+ {
+ m_fragShaderSource = shaderSource;
+ m_vertShaderSource =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out mediump vec4 v_coords;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = a_position;\n"
+ " v_coords = a_coords;\n"
+ "}\n";
+ }
+}
+
+ShaderReturnCase::~ShaderReturnCase (void)
+{
+}
+
+class ReturnTestUniformSetup : public UniformSetup
+{
+public:
+ ReturnTestUniformSetup (const BaseUniformType uniformType)
+ : m_uniformType(uniformType)
+ {}
+ virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
+ {
+ instance.useUniform(0u, m_uniformType);
+ }
+
+private:
+ const BaseUniformType m_uniformType;
+};
+
+// Test case builders.
+
+de::MovePtr<ShaderReturnCase> makeConditionalReturnInFuncCase (tcu::TestContext& context, const std::string& name, const std::string& description, ReturnMode returnMode, bool isVertex)
+{
+ tcu::StringTemplate tmpl(
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
+ "${EXTRADECL}\n"
+ "${COORDPREC} vec4 getColor (void)\n"
+ "{\n"
+ " if (${RETURNCOND})\n"
+ " return vec4(${COORDS}.xyz, 1.0);\n"
+ " return vec4(${COORDS}.wzy, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ "${POSITIONWRITE}"
+ " ${OUTPUT} = getColor();\n"
+ "}\n");
+
+ const char* coords = isVertex ? "a_coords" : "v_coords";
+
+ std::map<std::string, std::string> params;
+
+ params["COORDLOC"] = isVertex ? "1" : "0";
+ params["COORDPREC"] = isVertex ? "highp" : "mediump";
+ params["OUTPUT"] = isVertex ? "v_color" : "o_color";
+ params["COORDS"] = coords;
+ params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
+ params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
+
+ switch (returnMode)
+ {
+ case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
+ case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
+ case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
+ default: DE_ASSERT(DE_FALSE);
+ }
+
+ return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), DE_NULL));
+}
+
+de::MovePtr<ShaderReturnCase> makeOutputWriteReturnCase (tcu::TestContext& context, const std::string& name, const std::string& description, bool inFunction, ReturnMode returnMode, bool isVertex)
+{
+ tcu::StringTemplate tmpl(
+ inFunction
+ ?
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
+ "${EXTRADECL}\n"
+ "void myfunc (void)\n"
+ "{\n"
+ " ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
+ " if (${RETURNCOND})\n"
+ " return;\n"
+ " ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ "${POSITIONWRITE}"
+ " myfunc();\n"
+ "}\n"
+ :
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
+ "${EXTRADECL}\n"
+ "void main ()\n"
+ "{\n"
+ "${POSITIONWRITE}"
+ " ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
+ " if (${RETURNCOND})\n"
+ " return;\n"
+ " ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
+ "}\n");
+
+ const char* coords = isVertex ? "a_coords" : "v_coords";
+
+ std::map<std::string, std::string> params;
+
+ params["COORDLOC"] = isVertex ? "1" : "0";
+ params["COORDPREC"] = isVertex ? "highp" : "mediump";
+ params["COORDS"] = coords;
+ params["OUTPUT"] = isVertex ? "v_color" : "o_color";
+ params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
+ params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
+
+ switch (returnMode)
+ {
+ case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
+ case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
+ case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
+ default: DE_ASSERT(DE_FALSE);
+ }
+
+ return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), DE_NULL));
+}
+
+de::MovePtr<ShaderReturnCase> makeReturnInLoopCase (tcu::TestContext& context, const std::string& name, const std::string& description, bool isDynamicLoop, ReturnMode returnMode, bool isVertex)
+{
+ tcu::StringTemplate tmpl(
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
+ "layout(binding = 0, std140) uniform something { mediump int ui_one; };\n"
+ "${EXTRADECL}\n"
+ "${COORDPREC} vec4 getCoords (void)\n"
+ "{\n"
+ " ${COORDPREC} vec4 coords = ${COORDS};\n"
+ " for (int i = 0; i < ${ITERLIMIT}; i++)\n"
+ " {\n"
+ " if (${RETURNCOND})\n"
+ " return coords;\n"
+ " coords = coords.wzyx;\n"
+ " }\n"
+ " return coords;\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ "${POSITIONWRITE}"
+ " ${OUTPUT} = vec4(getCoords().xyz, 1.0);\n"
+ "}\n");
+
+ const char* coords = isVertex ? "a_coords" : "v_coords";
+
+ std::map<std::string, std::string> params;
+
+ params["COORDLOC"] = isVertex ? "1" : "0";
+ params["COORDPREC"] = isVertex ? "highp" : "mediump";
+ params["OUTPUT"] = isVertex ? "v_color" : "o_color";
+ params["COORDS"] = coords;
+ params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
+ params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
+ params["ITERLIMIT"] = isDynamicLoop ? "ui_one" : "1";
+
+ switch (returnMode)
+ {
+ case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
+ case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
+ case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
+ default: DE_ASSERT(DE_FALSE);
+ }
+
+ return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), new ReturnTestUniformSetup(UI_ONE)));
+}
+
+static const char* getReturnModeName (ReturnMode mode)
+{
+ switch (mode)
+ {
+ case RETURNMODE_ALWAYS: return "always";
+ case RETURNMODE_NEVER: return "never";
+ case RETURNMODE_DYNAMIC: return "dynamic";
+ default:
+ DE_ASSERT(DE_FALSE);
+ return DE_NULL;
+ }
+}
+
+static const char* getReturnModeDesc (ReturnMode mode)
+{
+ switch (mode)
+ {
+ case RETURNMODE_ALWAYS: return "Always return";
+ case RETURNMODE_NEVER: return "Never return";
+ case RETURNMODE_DYNAMIC: return "Return based on coords";
+ default:
+ DE_ASSERT(DE_FALSE);
+ return DE_NULL;
+ }
+}
+
+class ShaderReturnTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderReturnTests (tcu::TestContext& context);
+ virtual ~ShaderReturnTests (void);
+ virtual void init (void);
+
+private:
+ ShaderReturnTests (const ShaderReturnTests&); // not allowed!
+ ShaderReturnTests& operator= (const ShaderReturnTests&); // not allowed!
+};
+
+ShaderReturnTests::ShaderReturnTests (tcu::TestContext& context)
+ : TestCaseGroup(context, "return", "Return Statement Tests")
+{
+}
+
+ShaderReturnTests::~ShaderReturnTests (void)
+{
+}
+
+void ShaderReturnTests::init (void)
+{
+ addChild(new ShaderReturnCase(m_testCtx, "single_return_vertex", "Single return statement in function", true,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out highp vec4 v_color;\n\n"
+ "vec4 getColor (void)\n"
+ "{\n"
+ " return vec4(a_coords.xyz, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = a_position;\n"
+ " v_color = getColor();\n"
+ "}\n", evalReturnAlways, DE_NULL));
+ addChild(new ShaderReturnCase(m_testCtx, "single_return_fragment", "Single return statement in function", false,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_coords;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n"
+ "mediump vec4 getColor (void)\n"
+ "{\n"
+ " return vec4(v_coords.xyz, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = getColor();\n"
+ "}\n", evalReturnAlways, DE_NULL));
+
+ // Conditional return statement in function.
+ for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
+ {
+ for (int isFragment = 0; isFragment < 2; isFragment++)
+ {
+ std::string name = std::string("conditional_return_") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
+ std::string description = std::string(getReturnModeDesc((ReturnMode)returnMode)) + " in function";
+ de::MovePtr<ShaderReturnCase> testCase (makeConditionalReturnInFuncCase(m_testCtx, name, description, (ReturnMode)returnMode, isFragment == 0));
+ addChild(testCase.release());
+ }
+ }
+
+ // Unconditional double return in function.
+ addChild(new ShaderReturnCase(m_testCtx, "double_return_vertex", "Unconditional double return in function", true,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out highp vec4 v_color;\n\n"
+ "vec4 getColor (void)\n"
+ "{\n"
+ " return vec4(a_coords.xyz, 1.0);\n"
+ " return vec4(a_coords.wzy, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = a_position;\n"
+ " v_color = getColor();\n"
+ "}\n", evalReturnAlways, DE_NULL));
+ addChild(new ShaderReturnCase(m_testCtx, "double_return_fragment", "Unconditional double return in function", false,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_coords;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n\n"
+ "mediump vec4 getColor (void)\n"
+ "{\n"
+ " return vec4(v_coords.xyz, 1.0);\n"
+ " return vec4(v_coords.wzy, 1.0);\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = getColor();\n"
+ "}\n", evalReturnAlways, DE_NULL));
+
+ // Last statement in main.
+ addChild(new ShaderReturnCase(m_testCtx, "last_statement_in_main_vertex", "Return as a final statement in main()", true,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out highp vec4 v_color;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = a_position;\n"
+ " v_color = vec4(a_coords.xyz, 1.0);\n"
+ " return;\n"
+ "}\n", evalReturnAlways, DE_NULL));
+ addChild(new ShaderReturnCase(m_testCtx, "last_statement_in_main_fragment", "Return as a final statement in main()", false,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_coords;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = vec4(v_coords.xyz, 1.0);\n"
+ " return;\n"
+ "}\n", evalReturnAlways, DE_NULL));
+
+ // Return between output variable writes.
+ for (int inFunc = 0; inFunc < 2; inFunc++)
+ {
+ for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
+ {
+ for (int isFragment = 0; isFragment < 2; isFragment++)
+ {
+ std::string name = std::string("output_write_") + (inFunc ? "in_func_" : "") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
+ std::string desc = std::string(getReturnModeDesc((ReturnMode)returnMode)) + (inFunc ? " in user-defined function" : " in main()") + " between output writes";
+ de::MovePtr<ShaderReturnCase> testCase = (makeOutputWriteReturnCase(m_testCtx, name, desc, inFunc != 0, (ReturnMode)returnMode, isFragment == 0));
+ addChild(testCase.release());
+ }
+ }
+ }
+
+ // Conditional return statement in loop.
+ for (int isDynamicLoop = 0; isDynamicLoop < 2; isDynamicLoop++)
+ {
+ for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
+ {
+ for (int isFragment = 0; isFragment < 2; isFragment++)
+ {
+ std::string name = std::string("return_in_") + (isDynamicLoop ? "dynamic" : "static") + "_loop_" + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
+ std::string description = std::string(getReturnModeDesc((ReturnMode)returnMode)) + " in loop";
+ de::MovePtr<ShaderReturnCase> testCase (makeReturnInLoopCase(m_testCtx, name, description, isDynamicLoop != 0, (ReturnMode)returnMode, isFragment == 0));
+ addChild(testCase.release());
+ }
+ }
+ }
+
+ // Unconditional return in infinite loop.
+ addChild(new ShaderReturnCase(m_testCtx, "return_in_infinite_loop_vertex", "Return in infinite loop", true,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out highp vec4 v_color;\n"
+ "layout(binding = 0, std140) uniform something { int ui_zero; };\n"
+ "highp vec4 getCoords (void)\n"
+ "{\n"
+ " for (int i = 1; i < 10; i += ui_zero)\n"
+ " return a_coords;\n"
+ " return a_coords.wzyx;\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " gl_Position = a_position;\n"
+ " v_color = vec4(getCoords().xyz, 1.0);\n"
+ " return;\n"
+ "}\n", evalReturnAlways, new ReturnTestUniformSetup(UI_ZERO)));
+ addChild(new ShaderReturnCase(m_testCtx, "return_in_infinite_loop_fragment", "Return in infinite loop", false,
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_coords;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n"
+ "layout(binding = 0, std140) uniform something { int ui_zero; };\n\n"
+ "mediump vec4 getCoords (void)\n"
+ "{\n"
+ " for (int i = 1; i < 10; i += ui_zero)\n"
+ " return v_coords;\n"
+ " return v_coords.wzyx;\n"
+ "}\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = vec4(getCoords().xyz, 1.0);\n"
+ " return;\n"
+ "}\n", evalReturnAlways, new ReturnTestUniformSetup(UI_ZERO)));
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createReturnTests (tcu::TestContext& testCtx)
+{
+ return new ShaderReturnTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDERRETURNTESTS_HPP
+#define _VKTSHADERRENDERRETURNTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader return statement tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createReturnTests (tcu::TestContext& testCtx);
+
+}
+}
+
+#endif // _VKTSHADERRENDERRETURNTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader struct tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderStructTests.hpp"
+#include "vktShaderRender.hpp"
+#include "tcuStringTemplate.hpp"
+#include "deMath.h"
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+class ShaderStructCase : public ShaderRenderCase
+{
+public:
+ ShaderStructCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ bool isVertexCase,
+ ShaderEvalFunc evalFunc,
+ UniformSetupFunc setupUniformsFunc,
+ const std::string& vertShaderSource,
+ const std::string& fragShaderSource);
+ ~ShaderStructCase (void);
+
+private:
+ ShaderStructCase (const ShaderStructCase&);
+ ShaderStructCase& operator= (const ShaderStructCase&);
+};
+
+ShaderStructCase::ShaderStructCase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const std::string& description,
+ bool isVertexCase,
+ ShaderEvalFunc evalFunc,
+ UniformSetupFunc setupUniformsFunc,
+ const std::string& vertShaderSource,
+ const std::string& fragShaderSource)
+ : ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, new UniformSetup(setupUniformsFunc), DE_NULL)
+{
+ m_vertShaderSource = vertShaderSource;
+ m_fragShaderSource = fragShaderSource;
+}
+
+ShaderStructCase::~ShaderStructCase (void)
+{
+}
+
+static de::MovePtr<ShaderStructCase> createStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, bool isVertexCase, ShaderEvalFunc evalFunc, UniformSetupFunc uniformFunc, const LineStream& shaderSrc)
+{
+ static std::string defaultVertSrc =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out mediump vec4 v_coords;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " v_coords = a_coords;\n"
+ " gl_Position = a_position;\n"
+ "}\n";
+ static std::string defaultFragSrc =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_color;\n"
+ "layout(location = 0) out mediump vec4 o_color;\n\n"
+ "void main (void)\n"
+ "{\n"
+ " o_color = v_color;\n"
+ "}\n";
+
+ // Fill in specialization parameters and build the shader source.
+ std::string vertSrc;
+ std::string fragSrc;
+ std::map<std::string, std::string> spParams;
+
+ if (isVertexCase)
+ {
+ spParams["HEADER"] =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in highp vec4 a_position;\n"
+ "layout(location = 1) in highp vec4 a_coords;\n"
+ "layout(location = 0) out mediump vec4 v_color;";
+ spParams["COORDS"] = "a_coords";
+ spParams["DST"] = "v_color";
+ spParams["ASSIGN_POS"] = "gl_Position = a_position;";
+
+ vertSrc = tcu::StringTemplate(shaderSrc.str()).specialize(spParams);
+ fragSrc = defaultFragSrc;
+ }
+ else
+ {
+ spParams["HEADER"] =
+ "#version 140\n"
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(location = 0) in mediump vec4 v_coords;\n"
+ "layout(location = 0) out mediump vec4 o_color;";
+ spParams["COORDS"] = "v_coords";
+ spParams["DST"] = "o_color";
+ spParams["ASSIGN_POS"] = "";
+
+ vertSrc = defaultVertSrc;
+ fragSrc = tcu::StringTemplate(shaderSrc.str()).specialize(spParams);
+ }
+
+ return de::MovePtr<ShaderStructCase>(new ShaderStructCase(testCtx, name, description, isVertexCase, evalFunc, uniformFunc, vertSrc, fragSrc));
+}
+
+class LocalStructTests : public tcu::TestCaseGroup
+{
+public:
+ LocalStructTests (tcu::TestContext& testCtx)
+ : TestCaseGroup(testCtx, "local", "Local structs")
+ {
+ }
+
+ ~LocalStructTests (void)
+ {
+ }
+
+ virtual void init (void);
+};
+
+void LocalStructTests::init (void)
+{
+ #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, SHADER_SRC, SET_UNIFORMS_BODY, EVAL_FUNC_BODY) \
+ do { \
+ struct SetUniforms_##NAME { static void setUniforms (ShaderRenderCaseInstance& instance, const tcu::Vec4&) SET_UNIFORMS_BODY }; \
+ struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY }; \
+ addChild(createStructCase(m_testCtx, #NAME "_vertex", DESCRIPTION, true, &Eval_##NAME::eval, &SetUniforms_##NAME::setUniforms, SHADER_SRC).release()); \
+ addChild(createStructCase(m_testCtx, #NAME "_fragment", DESCRIPTION, false, &Eval_##NAME::eval, &SetUniforms_##NAME::setUniforms, SHADER_SRC).release()); \
+ } while (deGetFalse())
+
+ LOCAL_STRUCT_CASE(basic, "Basic struct usage",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, vec3(0.0), ui_one);"
+ << " s.b = ${COORDS}.yzw;"
+ << " ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(nested, "Nested struct",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
+ << " s.b = T(ui_zero, ${COORDS}.yz);"
+ << " ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(array_member, "Struct with array member",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump float b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s;"
+ << " s.a = ${COORDS}.w;"
+ << " s.c = ui_one;"
+ << " s.b[0] = ${COORDS}.z;"
+ << " s.b[1] = ${COORDS}.y;"
+ << " s.b[2] = ${COORDS}.x;"
+ << " ${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(3, 2, 1);
+ });
+
+ LOCAL_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump float b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s;"
+ << " s.a = ${COORDS}.w;"
+ << " s.c = ui_one;"
+ << " s.b[0] = ${COORDS}.z;"
+ << " s.b[1] = ${COORDS}.y;"
+ << " s.b[2] = ${COORDS}.x;"
+ << " ${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(1,2,0);
+ });
+
+ LOCAL_STRUCT_CASE(struct_array, "Struct array",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[3];"
+ << " s[0] = S(${COORDS}.x, ui_zero);"
+ << " s[1].a = ${COORDS}.y;"
+ << " s[1].b = ui_one;"
+ << " s[2] = S(${COORDS}.z, ui_two);"
+ << " ${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 1, 0);
+ });
+
+ LOCAL_STRUCT_CASE(struct_array_dynamic_index, "Struct array with dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[3];"
+ << " s[0] = S(${COORDS}.x, ui_zero);"
+ << " s[1].a = ${COORDS}.y;"
+ << " s[1].b = ui_one;"
+ << " s[2] = S(${COORDS}.z, ui_two);"
+ << " ${DST} = vec4(s[ui_two].a, s[ui_one].a, s[ui_zero].a, s[ui_two].b - s[ui_one].b + s[ui_zero].b);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 1, 0);
+ });
+
+ LOCAL_STRUCT_CASE(nested_struct_array, "Nested struct array",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_fourth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[2];"
+ << ""
+ << " // S[0]"
+ << " s[0].a = ${COORDS}.x;"
+ << " s[0].b[0].a = uf_half;"
+ << " s[0].b[0].b[0] = ${COORDS}.xy;"
+ << " s[0].b[0].b[1] = ${COORDS}.zw;"
+ << " s[0].b[1].a = uf_third;"
+ << " s[0].b[1].b[0] = ${COORDS}.zw;"
+ << " s[0].b[1].b[1] = ${COORDS}.xy;"
+ << " s[0].b[2].a = uf_fourth;"
+ << " s[0].b[2].b[0] = ${COORDS}.xz;"
+ << " s[0].b[2].b[1] = ${COORDS}.yw;"
+ << " s[0].c = ui_zero;"
+ << ""
+ << " // S[1]"
+ << " s[1].a = ${COORDS}.w;"
+ << " s[1].b[0].a = uf_two;"
+ << " s[1].b[0].b[0] = ${COORDS}.xx;"
+ << " s[1].b[0].b[1] = ${COORDS}.yy;"
+ << " s[1].b[1].a = uf_three;"
+ << " s[1].b[1].b[0] = ${COORDS}.zz;"
+ << " s[1].b[1].b[1] = ${COORDS}.ww;"
+ << " s[1].b[2].a = uf_four;"
+ << " s[1].b[2].b[0] = ${COORDS}.yx;"
+ << " s[1].b[2].b[1] = ${COORDS}.wz;"
+ << " s[1].c = ui_one;"
+ << ""
+ << " mediump float r = (s[0].b[1].b[0].x + s[1].b[2].b[1].y) * s[0].b[0].a; // (z + z) * 0.5"
+ << " mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
+ << " mediump float b = (s[0].b[2].b[1].y + s[0].b[1].b[0].y + s[1].a) * s[0].b[1].a; // (w + w + w) * 0.333"
+ << " mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
+ << " ${DST} = vec4(r, g, b, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UF_TWO);
+ instance.useUniform(4u, UF_THREE);
+ instance.useUniform(5u, UF_FOUR);
+ instance.useUniform(6u, UF_HALF);
+ instance.useUniform(7u, UF_THIRD);
+ instance.useUniform(8u, UF_FOURTH);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 0, 3);
+ });
+
+ LOCAL_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_fourth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[2];"
+ << ""
+ << " // S[0]"
+ << " s[0].a = ${COORDS}.x;"
+ << " s[0].b[0].a = uf_half;"
+ << " s[0].b[0].b[0] = ${COORDS}.xy;"
+ << " s[0].b[0].b[1] = ${COORDS}.zw;"
+ << " s[0].b[1].a = uf_third;"
+ << " s[0].b[1].b[0] = ${COORDS}.zw;"
+ << " s[0].b[1].b[1] = ${COORDS}.xy;"
+ << " s[0].b[2].a = uf_fourth;"
+ << " s[0].b[2].b[0] = ${COORDS}.xz;"
+ << " s[0].b[2].b[1] = ${COORDS}.yw;"
+ << " s[0].c = ui_zero;"
+ << ""
+ << " // S[1]"
+ << " s[1].a = ${COORDS}.w;"
+ << " s[1].b[0].a = uf_two;"
+ << " s[1].b[0].b[0] = ${COORDS}.xx;"
+ << " s[1].b[0].b[1] = ${COORDS}.yy;"
+ << " s[1].b[1].a = uf_three;"
+ << " s[1].b[1].b[0] = ${COORDS}.zz;"
+ << " s[1].b[1].b[1] = ${COORDS}.ww;"
+ << " s[1].b[2].a = uf_four;"
+ << " s[1].b[2].b[0] = ${COORDS}.yx;"
+ << " s[1].b[2].b[1] = ${COORDS}.wz;"
+ << " s[1].c = ui_one;"
+ << ""
+ << " mediump float r = (s[0].b[ui_one].b[ui_one-1].x + s[ui_one].b[ui_two].b[ui_zero+1].y) * s[0].b[0].a; // (z + z) * 0.5"
+ << " mediump float g = s[ui_two-1].b[ui_two-2].b[ui_zero].y * s[0].b[ui_two].a * s[ui_one].b[2].a; // x * 0.25 * 4"
+ << " mediump float b = (s[ui_zero].b[ui_one+1].b[1].y + s[0].b[ui_one*ui_one].b[0].y + s[ui_one].a) * s[0].b[ui_two-ui_one].a; // (w + w + w) * 0.333"
+ << " mediump float a = float(s[ui_zero].c) + s[ui_one-ui_zero].b[ui_two].a - s[ui_zero+ui_one].b[ui_two-ui_one].a; // 0 + 4.0 - 3.0"
+ << " ${DST} = vec4(r, g, b, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UF_TWO);
+ instance.useUniform(4u, UF_THREE);
+ instance.useUniform(5u, UF_FOUR);
+ instance.useUniform(6u, UF_HALF);
+ instance.useUniform(7u, UF_THIRD);
+ instance.useUniform(8u, UF_FOURTH);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 0, 3);
+ });
+
+ LOCAL_STRUCT_CASE(parameter, "Struct as a function parameter",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "mediump vec4 myFunc (S s)"
+ << "{"
+ << " return vec4(s.a, s.b.x, s.b.y, s.c);"
+ << "}"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, vec3(0.0), ui_one);"
+ << " s.b = ${COORDS}.yzw;"
+ << " ${DST} = myFunc(s);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(parameter_nested, "Nested struct as a function parameter",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "mediump vec4 myFunc (S s)"
+ << "{"
+ << " return vec4(s.a, s.b.b, s.b.a + s.c);"
+ << "}"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
+ << " s.b = T(ui_zero, ${COORDS}.yz);"
+ << " ${DST} = myFunc(s);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(return, "Struct as a return value",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "S myFunc (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, vec3(0.0), ui_one);"
+ << " s.b = ${COORDS}.yzw;"
+ << " return s;"
+ << "}"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = myFunc();"
+ << " ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(return_nested, "Nested struct",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "S myFunc (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
+ << " s.b = T(ui_zero, ${COORDS}.yz);"
+ << " return s;"
+ << "}"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = myFunc();"
+ << " ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 1, 2);
+ });
+
+ LOCAL_STRUCT_CASE(conditional_assignment, "Conditional struct assignment",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { mediump float uf_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
+ << " if (uf_one > 0.0)"
+ << " s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
+ << " ${DST} = vec4(s.a, s.b.xy, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UF_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(3, 2, 1);
+ });
+
+ LOCAL_STRUCT_CASE(loop_assignment, "Struct assignment in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
+ << " for (int i = 0; i < 3; i++)"
+ << " {"
+ << " if (i == 1)"
+ << " s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
+ << " }"
+ << " ${DST} = vec4(s.a, s.b.xy, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(3, 2, 1);
+ });
+
+ LOCAL_STRUCT_CASE(dynamic_loop_assignment, "Struct assignment in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_three; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
+ << " for (int i = 0; i < ui_three; i++)"
+ << " {"
+ << " if (i == ui_one)"
+ << " s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
+ << " }"
+ << " ${DST} = vec4(s.a, s.b.xy, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_THREE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(3, 2, 1);
+ });
+
+ LOCAL_STRUCT_CASE(nested_conditional_assignment, "Conditional assignment of nested struct",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { mediump float uf_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
+ << " if (uf_one > 0.0)"
+ << " s.b = T(ui_zero, ${COORDS}.zw);"
+ << " ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UF_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 2, 3);
+ });
+
+ LOCAL_STRUCT_CASE(nested_loop_assignment, "Nested struct assignment in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { mediump float uf_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
+ << " for (int i = 0; i < 3; i++)"
+ << " {"
+ << " if (i == 1)"
+ << " s.b = T(ui_zero, ${COORDS}.zw);"
+ << " }"
+ << " ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UF_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 2, 3);
+ });
+
+ LOCAL_STRUCT_CASE(nested_dynamic_loop_assignment, "Nested struct assignment in dynamic loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_three; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
+ << " for (int i = 0; i < ui_three; i++)"
+ << " {"
+ << " if (i == ui_one)"
+ << " s.b = T(ui_zero, ${COORDS}.zw);"
+ << " }"
+ << " ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_THREE);
+ instance.useUniform(3u, UF_ONE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(0, 2, 3);
+ });
+
+ LOCAL_STRUCT_CASE(loop_struct_array, "Struct array usage in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[3];"
+ << " s[0] = S(${COORDS}.x, ui_zero);"
+ << " s[1].a = ${COORDS}.y;"
+ << " s[1].b = -ui_one;"
+ << " s[2] = S(${COORDS}.z, ui_two);"
+ << ""
+ << " mediump float rgb[3];"
+ << " int alpha = 0;"
+ << " for (int i = 0; i < 3; i++)"
+ << " {"
+ << " rgb[i] = s[2-i].a;"
+ << " alpha += s[i].b;"
+ << " }"
+ << " ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 1, 0);
+ });
+
+ LOCAL_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_fourth; };"
+ << "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_sixth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[2];"
+ << ""
+ << " // S[0]"
+ << " s[0].a = ${COORDS}.x;"
+ << " s[0].b[0].a = uf_half;"
+ << " s[0].b[0].b[0] = ${COORDS}.yx;"
+ << " s[0].b[0].b[1] = ${COORDS}.zx;"
+ << " s[0].b[1].a = uf_third;"
+ << " s[0].b[1].b[0] = ${COORDS}.yy;"
+ << " s[0].b[1].b[1] = ${COORDS}.wy;"
+ << " s[0].b[2].a = uf_fourth;"
+ << " s[0].b[2].b[0] = ${COORDS}.zx;"
+ << " s[0].b[2].b[1] = ${COORDS}.zy;"
+ << " s[0].c = ui_zero;"
+ << ""
+ << " // S[1]"
+ << " s[1].a = ${COORDS}.w;"
+ << " s[1].b[0].a = uf_two;"
+ << " s[1].b[0].b[0] = ${COORDS}.zx;"
+ << " s[1].b[0].b[1] = ${COORDS}.zy;"
+ << " s[1].b[1].a = uf_three;"
+ << " s[1].b[1].b[0] = ${COORDS}.zz;"
+ << " s[1].b[1].b[1] = ${COORDS}.ww;"
+ << " s[1].b[2].a = uf_four;"
+ << " s[1].b[2].b[0] = ${COORDS}.yx;"
+ << " s[1].b[2].b[1] = ${COORDS}.wz;"
+ << " s[1].c = ui_one;"
+ << ""
+ << " mediump float r = 0.0; // (x*3 + y*3) / 6.0"
+ << " mediump float g = 0.0; // (y*3 + z*3) / 6.0"
+ << " mediump float b = 0.0; // (z*3 + w*3) / 6.0"
+ << " mediump float a = 1.0;"
+ << " for (int i = 0; i < 2; i++)"
+ << " {"
+ << " for (int j = 0; j < 3; j++)"
+ << " {"
+ << " r += s[0].b[j].b[i].y;"
+ << " g += s[i].b[j].b[0].x;"
+ << " b += s[i].b[j].b[1].x;"
+ << " a *= s[i].b[j].a;"
+ << " }"
+ << " }"
+ << " ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UF_TWO);
+ instance.useUniform(4u, UF_THREE);
+ instance.useUniform(5u, UF_FOUR);
+ instance.useUniform(6u, UF_HALF);
+ instance.useUniform(7u, UF_THIRD);
+ instance.useUniform(8u, UF_FOURTH);
+ instance.useUniform(9u, UF_SIXTH);
+ },
+ {
+ c.color.xyz() = (c.coords.swizzle(0, 1, 2) + c.coords.swizzle(1, 2, 3)) * 0.5f;
+ });
+
+ LOCAL_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[3];"
+ << " s[0] = S(${COORDS}.x, ui_zero);"
+ << " s[1].a = ${COORDS}.y;"
+ << " s[1].b = -ui_one;"
+ << " s[2] = S(${COORDS}.z, ui_two);"
+ << ""
+ << " mediump float rgb[3];"
+ << " int alpha = 0;"
+ << " for (int i = 0; i < ui_three; i++)"
+ << " {"
+ << " rgb[i] = s[2-i].a;"
+ << " alpha += s[i].b;"
+ << " }"
+ << " ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UI_THREE);
+ },
+ {
+ c.color.xyz() = c.coords.swizzle(2, 1, 0);
+ });
+
+ LOCAL_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_fourth; };"
+ << "layout (std140, set = 0, binding = 10) uniform buffer10 { mediump float uf_sixth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S s[2];"
+ << ""
+ << " s[0].a = ${COORDS}.x;"
+ << " s[0].b[0].a = uf_half;"
+ << " s[0].b[0].b[0] = ${COORDS}.yx;"
+ << " s[0].b[0].b[1] = ${COORDS}.zx;"
+ << " s[0].b[1].a = uf_third;"
+ << " s[0].b[1].b[0] = ${COORDS}.yy;"
+ << " s[0].b[1].b[1] = ${COORDS}.wy;"
+ << " s[0].b[2].a = uf_fourth;"
+ << " s[0].b[2].b[0] = ${COORDS}.zx;"
+ << " s[0].b[2].b[1] = ${COORDS}.zy;"
+ << " s[0].c = ui_zero;"
+ << ""
+ << " s[1].a = ${COORDS}.w;"
+ << " s[1].b[0].a = uf_two;"
+ << " s[1].b[0].b[0] = ${COORDS}.zx;"
+ << " s[1].b[0].b[1] = ${COORDS}.zy;"
+ << " s[1].b[1].a = uf_three;"
+ << " s[1].b[1].b[0] = ${COORDS}.zz;"
+ << " s[1].b[1].b[1] = ${COORDS}.ww;"
+ << " s[1].b[2].a = uf_four;"
+ << " s[1].b[2].b[0] = ${COORDS}.yx;"
+ << " s[1].b[2].b[1] = ${COORDS}.wz;"
+ << " s[1].c = ui_one;"
+ << ""
+ << " mediump float r = 0.0; // (x*3 + y*3) / 6.0"
+ << " mediump float g = 0.0; // (y*3 + z*3) / 6.0"
+ << " mediump float b = 0.0; // (z*3 + w*3) / 6.0"
+ << " mediump float a = 1.0;"
+ << " for (int i = 0; i < ui_two; i++)"
+ << " {"
+ << " for (int j = 0; j < ui_three; j++)"
+ << " {"
+ << " r += s[0].b[j].b[i].y;"
+ << " g += s[i].b[j].b[0].x;"
+ << " b += s[i].b[j].b[1].x;"
+ << " a *= s[i].b[j].a;"
+ << " }"
+ << " }"
+ << " ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UI_THREE);
+ instance.useUniform(4u, UF_TWO);
+ instance.useUniform(5u, UF_THREE);
+ instance.useUniform(6u, UF_FOUR);
+ instance.useUniform(7u, UF_HALF);
+ instance.useUniform(8u, UF_THIRD);
+ instance.useUniform(9u, UF_FOURTH);
+ instance.useUniform(10u, UF_SIXTH);
+ },
+ {
+ c.color.xyz() = (c.coords.swizzle(0, 1, 2) + c.coords.swizzle(1, 2, 3)) * 0.5f;
+ });
+
+ LOCAL_STRUCT_CASE(basic_equal, "Basic struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S a = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y), 2.3), ui_one);"
+ << " S b = S(floor(${COORDS}.x+0.5), vec3(0.0, floor(${COORDS}.y), 2.3), ui_one);"
+ << " S c = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y+0.5), 2.3), ui_one);"
+ << " S d = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y), 2.3), ui_two);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a == b) ${DST}.x = 1.0;"
+ << " if (a == c) ${DST}.y = 1.0;"
+ << " if (a == d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ instance.useUniform(1u, UI_TWO);
+ },
+ {
+ if (deFloatFloor(c.coords[0]) == deFloatFloor(c.coords[0] + 0.5f))
+ c.color.x() = 1.0f;
+ if (deFloatFloor(c.coords[1]) == deFloatFloor(c.coords[1] + 0.5f))
+ c.color.y() = 1.0f;
+ });
+
+ LOCAL_STRUCT_CASE(basic_not_equal, "Basic struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S a = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y), 2.3), ui_one);"
+ << " S b = S(floor(${COORDS}.x+0.5), vec3(0.0, floor(${COORDS}.y), 2.3), ui_one);"
+ << " S c = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y+0.5), 2.3), ui_one);"
+ << " S d = S(floor(${COORDS}.x), vec3(0.0, floor(${COORDS}.y), 2.3), ui_two);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a != b) ${DST}.x = 1.0;"
+ << " if (a != c) ${DST}.y = 1.0;"
+ << " if (a != d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ instance.useUniform(1u, UI_TWO);
+ },
+ {
+ if (deFloatFloor(c.coords[0]) != deFloatFloor(c.coords[0] + 0.5f))
+ c.color.x() = 1.0f;
+ if (deFloatFloor(c.coords[1]) != deFloatFloor(c.coords[1] + 0.5f))
+ c.color.y() = 1.0f;
+ c.color.z() = 1.0f;
+ });
+
+ LOCAL_STRUCT_CASE(nested_equal, "Nested struct struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct T {"
+ << " mediump vec3 a;"
+ << " int b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S a = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_one), 1);"
+ << " S b = S(floor(${COORDS}.x+0.5), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_one), 1);"
+ << " S c = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y+0.5), 2.3), ui_one), 1);"
+ << " S d = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_two), 1);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a == b) ${DST}.x = 1.0;"
+ << " if (a == c) ${DST}.y = 1.0;"
+ << " if (a == d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ instance.useUniform(1u, UI_TWO);
+ },
+ {
+ if (deFloatFloor(c.coords[0]) == deFloatFloor(c.coords[0] + 0.5f))
+ c.color.x() = 1.0f;
+ if (deFloatFloor(c.coords[1]) == deFloatFloor(c.coords[1] + 0.5f))
+ c.color.y() = 1.0f;
+ });
+
+ LOCAL_STRUCT_CASE(nested_not_equal, "Nested struct struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct T {"
+ << " mediump vec3 a;"
+ << " int b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S a = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_one), 1);"
+ << " S b = S(floor(${COORDS}.x+0.5), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_one), 1);"
+ << " S c = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y+0.5), 2.3), ui_one), 1);"
+ << " S d = S(floor(${COORDS}.x), T(vec3(0.0, floor(${COORDS}.y), 2.3), ui_two), 1);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a != b) ${DST}.x = 1.0;"
+ << " if (a != c) ${DST}.y = 1.0;"
+ << " if (a != d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+ instance.useUniform(1u, UI_TWO);
+ },
+ {
+ if (deFloatFloor(c.coords[0]) != deFloatFloor(c.coords[0] + 0.5f))
+ c.color.x() = 1.0f;
+ if (deFloatFloor(c.coords[1]) != deFloatFloor(c.coords[1] + 0.5f))
+ c.color.y() = 1.0f;
+ c.color.z() = 1.0f;
+ });
+}
+
+class UniformStructTests : public tcu::TestCaseGroup
+{
+public:
+ UniformStructTests (tcu::TestContext& testCtx)
+ : TestCaseGroup(testCtx, "uniform", "Uniform structs")
+ {
+ }
+
+ ~UniformStructTests (void)
+ {
+ }
+
+ virtual void init (void);
+};
+
+void UniformStructTests::init (void)
+{
+ #define UNIFORM_STRUCT_CASE(NAME, DESCRIPTION, SHADER_SRC, SET_UNIFORMS_BODY, EVAL_FUNC_BODY) \
+ do { \
+ struct SetUniforms_##NAME { static void setUniforms (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) SET_UNIFORMS_BODY }; \
+ struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY }; \
+ addChild(createStructCase(m_testCtx, #NAME "_vertex", DESCRIPTION, true, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC).release()); \
+ addChild(createStructCase(m_testCtx, #NAME "_fragment", DESCRIPTION, false, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC).release()); \
+ } while (deGetFalse())
+
+ UNIFORM_STRUCT_CASE(basic, "Basic struct usage",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { S s; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+
+ struct S {
+ float a;
+ float _padding1[3];
+ tcu::Vec3 b;
+ int c;
+ };
+
+ S s;
+ s.a = constCoords.x();
+ s.b = constCoords.swizzle(1, 2, 3);
+ s.c = 1;
+ instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(0, 1, 2);
+ });
+
+ UNIFORM_STRUCT_CASE(nested, "Nested struct",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << ""
+ << "struct T {"
+ << " int a;"
+ << " mediump vec2 b;"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b;"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { S s; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+
+ struct T {
+ int a;
+ float _padding1[3];
+ tcu::Vec2 b;
+ float _padding2[2];
+ };
+
+ struct S {
+ float a;
+ float _padding1[3];
+ T b;
+ int c;
+ };
+
+ S s;
+ s.a = constCoords.x();
+ s.b.a = 0;
+ s.b.b = constCoords.swizzle(1, 2);
+ s.c = 1;
+ instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,sizeof(S), &s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(0, 1, 2);
+ });
+
+ UNIFORM_STRUCT_CASE(array_member, "Struct with array member",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump float b[3];"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { S s; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ONE);
+
+ struct paddedFloat {
+ float value;
+ float _padding[3];
+ };
+
+ struct S {
+ paddedFloat a;
+ paddedFloat b[3];
+ int c;
+ };
+
+ S s;
+ s.a.value = constCoords.w();
+ s.b[0].value = constCoords.z();
+ s.b[1].value = constCoords.y();
+ s.b[2].value = constCoords.x();
+ s.c = 1;
+ instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,sizeof(S), &s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(3, 2, 1);
+ });
+
+ UNIFORM_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump float b[3];"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S s; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+
+ struct paddedFloat {
+ float value;
+ float _padding[3];
+ };
+
+ struct S {
+ paddedFloat a;
+ paddedFloat b[3];
+ int c;
+ };
+
+ S s;
+ s.a.value = constCoords.w();
+ s.b[0].value = constCoords.z();
+ s.b[1].value = constCoords.y();
+ s.b[2].value = constCoords.x();
+ s.c = 1;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(1, 2, 0);
+ });
+
+ UNIFORM_STRUCT_CASE(struct_array, "Struct array",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+
+ struct S {
+ float a;
+ int b;
+ float _padding1[2];
+ };
+
+ S s[3];
+ s[0].a = constCoords.x();
+ s[0].b = 0;
+ s[1].a = constCoords.y();
+ s[1].b = 1;
+ s[2].a = constCoords.z();
+ s[2].b = 2;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 * sizeof(S), s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
+ });
+
+ UNIFORM_STRUCT_CASE(struct_array_dynamic_index, "Struct array with dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " ${DST} = vec4(s[ui_two].a, s[ui_one].a, s[ui_zero].a, s[ui_two].b - s[ui_one].b + s[ui_zero].b);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+
+ struct S {
+ float a;
+ int b;
+ float _padding1[2];
+ };
+
+ S s[3];
+ s[0].a = constCoords.x();
+ s[0].b = 0;
+ s[1].a = constCoords.y();
+ s[1].b = 1;
+ s[2].a = constCoords.z();
+ s[2].b = 2;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 * sizeof(S), s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
+ });
+
+ UNIFORM_STRUCT_CASE(nested_struct_array, "Nested struct array",
+ LineStream()
+ << "${HEADER}"
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { S s[2]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float r = (s[0].b[1].b[0].x + s[1].b[2].b[1].y) * s[0].b[0].a; // (z + z) * 0.5"
+ << " mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
+ << " mediump float b = (s[0].b[2].b[1].y + s[0].b[1].b[0].y + s[1].a) * s[0].b[1].a; // (w + w + w) * 0.333"
+ << " mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
+ << " ${DST} = vec4(r, g, b, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+
+ struct T {
+ float a;
+ float _padding1[3];
+ tcu::Vec4 b[2];
+ };
+
+ struct S {
+ float a;
+ float _padding1[3];
+ T b[3];
+ int c;
+ float _padding2[3];
+ };
+
+ S s[2];
+ s[0].a = constCoords.x();
+ s[0].b[0].a = 0.5f;
+ s[0].b[0].b[0] = constCoords.swizzle(0,1,0,0);
+ s[0].b[0].b[1] = constCoords.swizzle(2,3,0,0);
+ s[0].b[1].a = 1.0f / 3.0f;
+ s[0].b[1].b[0] = constCoords.swizzle(2,3,0,0);
+ s[0].b[1].b[1] = constCoords.swizzle(0,1,0,0);
+ s[0].b[2].a = 1.0f / 4.0f;
+ s[0].b[2].b[0] = constCoords.swizzle(0,2,0,0);
+ s[0].b[2].b[1] = constCoords.swizzle(1,3,0,0);
+ s[0].c = 0;
+
+ s[1].a = constCoords.w();
+ s[1].b[0].a = 2.0f;
+ s[1].b[0].b[0] = constCoords.swizzle(0,0,0,0);
+ s[1].b[0].b[1] = constCoords.swizzle(1,1,0,0);
+ s[1].b[1].a = 3.0f;
+ s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
+ s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
+ s[1].b[2].a = 4.0f;
+ s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
+ s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
+ s[1].c = 1;
+
+ instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 0, 3);
+ });
+
+ UNIFORM_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << "layout (set = 0, binding = 3) uniform buffer3 { S s[2]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float r = (s[0].b[ui_one].b[ui_one-1].x + s[ui_one].b[ui_two].b[ui_zero+1].y) * s[0].b[0].a; // (z + z) * 0.5"
+ << " mediump float g = s[ui_two-1].b[ui_two-2].b[ui_zero].y * s[0].b[ui_two].a * s[ui_one].b[2].a; // x * 0.25 * 4"
+ << " mediump float b = (s[ui_zero].b[ui_one+1].b[1].y + s[0].b[ui_one*ui_one].b[0].y + s[ui_one].a) * s[0].b[ui_two-ui_one].a; // (w + w + w) * 0.333"
+ << " mediump float a = float(s[ui_zero].c) + s[ui_one-ui_zero].b[ui_two].a - s[ui_zero+ui_one].b[ui_two-ui_one].a; // 0 + 4.0 - 3.0"
+ << " ${DST} = vec4(r, g, b, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ struct T {
+ float a;
+ float _padding1[3];
+ tcu::Vec4 b[2];
+ };
+
+ struct S {
+ float a;
+ float _padding1[3];
+ T b[3];
+ int c;
+ float _padding2[3];
+ };
+
+ S s[2];
+ s[0].a = constCoords.x();
+ s[0].b[0].a = 0.5f;
+ s[0].b[0].b[0] = constCoords.swizzle(0,1,0,0);
+ s[0].b[0].b[1] = constCoords.swizzle(2,3,0,0);
+ s[0].b[1].a = 1.0f / 3.0f;
+ s[0].b[1].b[0] = constCoords.swizzle(2,3,0,0);
+ s[0].b[1].b[1] = constCoords.swizzle(0,1,0,0);
+ s[0].b[2].a = 1.0f / 4.0f;
+ s[0].b[2].b[0] = constCoords.swizzle(0,2,0,0);
+ s[0].b[2].b[1] = constCoords.swizzle(1,3,0,0);
+ s[0].c = 0;
+
+ s[1].a = constCoords.w();
+ s[1].b[0].a = 2.0f;
+ s[1].b[0].b[0] = constCoords.swizzle(0,0,0,0);
+ s[1].b[0].b[1] = constCoords.swizzle(1,1,0,0);
+ s[1].b[1].a = 3.0f;
+ s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
+ s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
+ s[1].b[2].a = 4.0f;
+ s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
+ s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
+ s[1].c = 1;
+
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 0, 3);
+ });
+ UNIFORM_STRUCT_CASE(loop_struct_array, "Struct array usage in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float rgb[3];"
+ << " int alpha = 0;"
+ << " for (int i = 0; i < 3; i++)"
+ << " {"
+ << " rgb[i] = s[2-i].a;"
+ << " alpha += s[i].b;"
+ << " }"
+ << " ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+
+ struct S {
+ float a;
+ int b;
+ float _padding1[2];
+ };
+
+ S s[3];
+ s[0].a = constCoords.x();
+ s[0].b = 0;
+ s[1].a = constCoords.y();
+ s[1].b = -1;
+ s[2].a = constCoords.z();
+ s[2].b = 2;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u * sizeof(S), s);
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
+ });
+
+ UNIFORM_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_fourth; };"
+ << "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_sixth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 10) uniform buffer10 { S s[2]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float r = 0.0; // (x*3 + y*3) / 6.0"
+ << " mediump float g = 0.0; // (y*3 + z*3) / 6.0"
+ << " mediump float b = 0.0; // (z*3 + w*3) / 6.0"
+ << " mediump float a = 1.0;"
+ << " for (int i = 0; i < 2; i++)"
+ << " {"
+ << " for (int j = 0; j < 3; j++)"
+ << " {"
+ << " r += s[0].b[j].b[i].y;"
+ << " g += s[i].b[j].b[0].x;"
+ << " b += s[i].b[j].b[1].x;"
+ << " a *= s[i].b[j].a;"
+ << " }"
+ << " }"
+ << " ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UF_TWO);
+ instance.useUniform(4u, UF_THREE);
+ instance.useUniform(5u, UF_FOUR);
+ instance.useUniform(6u, UF_HALF);
+ instance.useUniform(7u, UF_THIRD);
+ instance.useUniform(8u, UF_FOURTH);
+ instance.useUniform(9u, UF_SIXTH);
+
+ struct T {
+ float a;
+ float _padding1[3];
+ tcu::Vec4 b[2];
+ };
+
+ struct S {
+ float a;
+ float _padding1[3];
+ T b[3];
+ int c;
+ float _padding2[3];
+ };
+
+ S s[2];
+ s[0].a = constCoords.x();
+ s[0].b[0].a = 0.5f;
+ s[0].b[0].b[0] = constCoords.swizzle(1,0,0,0);
+ s[0].b[0].b[1] = constCoords.swizzle(2,0,0,0);
+ s[0].b[1].a = 1.0f / 3.0f;
+ s[0].b[1].b[0] = constCoords.swizzle(1,1,0,0);
+ s[0].b[1].b[1] = constCoords.swizzle(3,1,0,0);
+ s[0].b[2].a = 1.0f / 4.0f;
+ s[0].b[2].b[0] = constCoords.swizzle(2,1,0,0);
+ s[0].b[2].b[1] = constCoords.swizzle(2,1,0,0);
+ s[0].c = 0;
+
+ s[1].a = constCoords.w();
+ s[1].b[0].a = 2.0f;
+ s[1].b[0].b[0] = constCoords.swizzle(2,0,0,0);
+ s[1].b[0].b[1] = constCoords.swizzle(2,1,0,0);
+ s[1].b[1].a = 3.0f;
+ s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
+ s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
+ s[1].b[2].a = 4.0f;
+ s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
+ s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
+ s[1].c = 1;
+
+ instance.addUniform(10u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
+
+ },
+ {
+ c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f;
+ });
+
+ UNIFORM_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump int b;"
+ << "};"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { S s[3]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float rgb[3];"
+ << " int alpha = 0;"
+ << " for (int i = 0; i < ui_three; i++)"
+ << " {"
+ << " rgb[i] = s[2-i].a;"
+ << " alpha += s[i].b;"
+ << " }"
+ << " ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UI_THREE);
+
+ struct S {
+ float a;
+ int b;
+ float _padding1[2];
+ };
+
+ S s[3];
+ s[0].a = constCoords.x();
+ s[0].b = 0;
+ s[1].a = constCoords.y();
+ s[1].b = -1;
+ s[2].a = constCoords.z();
+ s[2].b = 2;
+ instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u * sizeof(S), s);
+
+ },
+ {
+ c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
+ });
+
+ UNIFORM_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_two; };"
+ << "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_three; };"
+ << "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_four; };"
+ << "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_half; };"
+ << "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_third; };"
+ << "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_fourth; };"
+ << "layout (std140, set = 0, binding = 10) uniform buffer10 { mediump float uf_sixth; };"
+ << ""
+ << "struct T {"
+ << " mediump float a;"
+ << " mediump vec2 b[2];"
+ << "};"
+ << "struct S {"
+ << " mediump float a;"
+ << " T b[3];"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 10) uniform buffer11 { S s[2]; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " mediump float r = 0.0; // (x*3 + y*3) / 6.0"
+ << " mediump float g = 0.0; // (y*3 + z*3) / 6.0"
+ << " mediump float b = 0.0; // (z*3 + w*3) / 6.0"
+ << " mediump float a = 1.0;"
+ << " for (int i = 0; i < ui_two; i++)"
+ << " {"
+ << " for (int j = 0; j < ui_three; j++)"
+ << " {"
+ << " r += s[0].b[j].b[i].y;"
+ << " g += s[i].b[j].b[0].x;"
+ << " b += s[i].b[j].b[1].x;"
+ << " a *= s[i].b[j].a;"
+ << " }"
+ << " }"
+ << " ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ instance.useUniform(0u, UI_ZERO);
+ instance.useUniform(1u, UI_ONE);
+ instance.useUniform(2u, UI_TWO);
+ instance.useUniform(3u, UI_THREE);
+ instance.useUniform(4u, UF_TWO);
+ instance.useUniform(5u, UF_THREE);
+ instance.useUniform(6u, UF_FOUR);
+ instance.useUniform(7u, UF_HALF);
+ instance.useUniform(8u, UF_THIRD);
+ instance.useUniform(9u, UF_FOURTH);
+ instance.useUniform(10u, UF_SIXTH);
+
+ struct T {
+ float a;
+ float _padding1[3];
+ tcu::Vec4 b[2];
+ };
+
+ struct S {
+ float a;
+ float _padding1[3];
+ T b[3];
+ int c;
+ float _padding2[3];
+ };
+
+ S s[2];
+ s[0].a = constCoords.x();
+ s[0].b[0].a = 0.5f;
+ s[0].b[0].b[0] = constCoords.swizzle(1,0,0,0);
+ s[0].b[0].b[1] = constCoords.swizzle(2,0,0,0);
+ s[0].b[1].a = 1.0f / 3.0f;
+ s[0].b[1].b[0] = constCoords.swizzle(1,1,0,0);
+ s[0].b[1].b[1] = constCoords.swizzle(3,1,0,0);
+ s[0].b[2].a = 1.0f / 4.0f;
+ s[0].b[2].b[0] = constCoords.swizzle(2,1,0,0);
+ s[0].b[2].b[1] = constCoords.swizzle(2,1,0,0);
+ s[0].c = 0;
+
+ s[1].a = constCoords.w();
+ s[1].b[0].a = 2.0f;
+ s[1].b[0].b[0] = constCoords.swizzle(2,0,0,0);
+ s[1].b[0].b[1] = constCoords.swizzle(2,1,0,0);
+ s[1].b[1].a = 3.0f;
+ s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
+ s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
+ s[1].b[2].a = 4.0f;
+ s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
+ s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
+ s[1].c = 1;
+
+ instance.addUniform(11u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
+
+ },
+ {
+ c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f;
+ });
+
+ UNIFORM_STRUCT_CASE(equal, "Struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { mediump float uf_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { S a; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S b; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { S c; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a == b) ${DST}.x = 1.0;"
+ << " if (a == c) ${DST}.y = 1.0;"
+ << " if (a == d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ DE_UNREF(constCoords);
+ instance.useUniform(0u, UF_ONE);
+ instance.useUniform(1u, UI_TWO);
+
+ struct S {
+ float a;
+ float _padding1[3];
+ tcu::Vec3 b;
+ int c;
+ };
+
+ S sa;
+ sa.a = 1.0f;
+ sa.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
+ sa.c = 2;
+ instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sa);
+
+ S sb;
+ sb.a = 1.0f;
+ sb.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
+ sb.c = 2;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sb);
+
+ S sc;
+ sc.a = 1.0f;
+ sc.b = tcu::Vec3(0.0f, 1.1f, 2.0f);
+ sc.c = 2;
+ instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sc);
+ },
+ {
+ c.color.xy() = tcu::Vec2(1.0f, 0.0f);
+ if (deFloatFloor(c.coords[1] + 1.0f) == deFloatFloor(1.1f))
+ c.color.z() = 1.0f;
+ });
+
+ UNIFORM_STRUCT_CASE(not_equal, "Struct equality",
+ LineStream()
+ << "${HEADER}"
+ << "layout (std140, set = 0, binding = 0) uniform buffer0 { mediump float uf_one; };"
+ << "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
+ << ""
+ << "struct S {"
+ << " mediump float a;"
+ << " mediump vec3 b;"
+ << " int c;"
+ << "};"
+ << "layout (std140, set = 0, binding = 2) uniform buffer2 { S a; };"
+ << "layout (std140, set = 0, binding = 3) uniform buffer3 { S b; };"
+ << "layout (std140, set = 0, binding = 4) uniform buffer4 { S c; };"
+ << ""
+ << "void main (void)"
+ << "{"
+ << " S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
+ << " ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+ << " if (a != b) ${DST}.x = 1.0;"
+ << " if (a != c) ${DST}.y = 1.0;"
+ << " if (a != d) ${DST}.z = 1.0;"
+ << " ${ASSIGN_POS}"
+ << "}",
+ {
+ DE_UNREF(constCoords);
+ instance.useUniform(0u, UF_ONE);
+ instance.useUniform(1u, UI_TWO);
+
+ struct S {
+ float a;
+ float _padding1[3];
+ tcu::Vec3 b;
+ int c;
+ };
+
+ S sa;
+ sa.a = 1.0f;
+ sa.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
+ sa.c = 2;
+ instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sa);
+
+ S sb;
+ sb.a = 1.0f;
+ sb.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
+ sb.c = 2;
+ instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sb);
+
+ S sc;
+ sc.a = 1.0f;
+ sc.b = tcu::Vec3(0.0f, 1.1f, 2.0f);
+ sc.c = 2;
+ instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sc);
+ },
+ {
+ c.color.xy() = tcu::Vec2(0.0f, 1.0f);
+ if (deFloatFloor(c.coords[1] + 1.0f) != deFloatFloor(1.1f))
+ c.color.z() = 1.0f;
+ });
+}
+
+class ShaderStructTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderStructTests (tcu::TestContext& context);
+ virtual ~ShaderStructTests (void);
+
+ virtual void init (void);
+
+private:
+ ShaderStructTests (const ShaderStructTests&); // not allowed!
+ ShaderStructTests& operator= (const ShaderStructTests&); // not allowed!
+};
+
+ShaderStructTests::ShaderStructTests (tcu::TestContext& testCtx)
+ : TestCaseGroup(testCtx, "struct", "Struct Tests")
+{
+}
+
+ShaderStructTests::~ShaderStructTests (void)
+{
+}
+
+void ShaderStructTests::init (void)
+{
+ addChild(new LocalStructTests(m_testCtx));
+ addChild(new UniformStructTests(m_testCtx));
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createStructTests (tcu::TestContext& testCtx)
+{
+ return new ShaderStructTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDERSTRUCTTESTS_HPP
+#define _VKTSHADERRENDERSTRUCTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader struct tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createStructTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERSTRUCTTESTS_HPP
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \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 "vktShaderRenderSwitchTests.hpp"
+#include "vktShaderRender.hpp"
+#include "tcuStringTemplate.hpp"
+#include "deMath.h"
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+static void setUniforms(ShaderRenderCaseInstance& instance, const tcu::Vec4&)
+{
+ instance.useUniform(0u, UI_TWO);
+}
+
+using std::string;
+
+class ShaderSwitchCase : public ShaderRenderCase
+{
+public:
+ ShaderSwitchCase (tcu::TestContext& testCtx,
+ const string& name,
+ const string& description,
+ bool isVertexCase,
+ const string& vtxSource,
+ const string& fragSource,
+ ShaderEvalFunc evalFunc,
+ UniformSetupFunc setupUniformsFunc);
+ virtual ~ShaderSwitchCase (void);
+};
+
+ShaderSwitchCase::ShaderSwitchCase (tcu::TestContext& testCtx,
+ const string& name,
+ const string& description,
+ bool isVertexCase,
+ const string& vtxSource,
+ const string& fragSource,
+ ShaderEvalFunc evalFunc,
+ UniformSetupFunc setupUniformsFunc)
+ : ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, new UniformSetup(setupUniformsFunc), DE_NULL)
+{
+ 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 de::MovePtr<ShaderSwitchCase> makeSwitchCase (tcu::TestContext& testCtx, const string& name, const string& desc, SwitchType type, bool isVertex, const LineStream& switchBody)
+{
+ std::ostringstream vtx;
+ std::ostringstream frag;
+ std::ostringstream& op = isVertex ? vtx : frag;
+
+ vtx << "#version 140\n"
+ << "#extension GL_ARB_separate_shader_objects : enable\n"
+ << "#extension GL_ARB_shading_language_420pack : enable\n"
+ << "layout(location = 0) in highp vec4 a_position;\n"
+ << "layout(location = 1) in highp vec4 a_coords;\n\n";
+ frag << "#version 140\n"
+ << "#extension GL_ARB_separate_shader_objects : enable\n"
+ << "#extension GL_ARB_shading_language_420pack : enable\n"
+ << "layout(location = 0) out mediump vec4 o_color;\n";
+
+ if (isVertex)
+ {
+ vtx << "layout(location = 0) out mediump vec4 v_color;\n";
+ frag << "layout(location = 0) in mediump vec4 v_color;\n";
+ }
+ else
+ {
+ vtx << "layout(location = 0) out highp vec4 v_coords;\n";
+ frag << "layout(location = 0) in highp vec4 v_coords;\n";
+ }
+
+ if (type == SWITCHTYPE_UNIFORM)
+ op << "layout (std140, set=0, binding=0) uniform buffer0 { 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.
+ std::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);
+ 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 de::MovePtr<ShaderSwitchCase>(new ShaderSwitchCase(testCtx, name, desc, isVertex, vtx.str(), frag.str(),
+ type == SWITCHTYPE_STATIC ? evalSwitchStatic :
+ type == SWITCHTYPE_UNIFORM ? evalSwitchUniform :
+ type == SWITCHTYPE_DYNAMIC ? evalSwitchDynamic : (ShaderEvalFunc)DE_NULL,
+ type == SWITCHTYPE_UNIFORM ? setUniforms : DE_NULL));
+}
+
+class ShaderSwitchTests : public tcu::TestCaseGroup
+{
+public:
+ ShaderSwitchTests (tcu::TestContext& context);
+ virtual ~ShaderSwitchTests (void);
+
+ virtual void init (void);
+
+private:
+ ShaderSwitchTests (const ShaderSwitchTests&); // not allowed!
+ ShaderSwitchTests& operator= (const ShaderSwitchTests&); // not allowed!
+
+ void makeSwitchCases (const string& name, const string& desc, const LineStream& switchBody);
+};
+
+ShaderSwitchTests::ShaderSwitchTests (tcu::TestContext& testCtx)
+ : tcu::TestCaseGroup (testCtx, "switch", "Switch statement tests")
+{
+}
+
+ShaderSwitchTests::~ShaderSwitchTests (void)
+{
+}
+
+void ShaderSwitchTests::makeSwitchCases (const string& name, const string& 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++)
+ {
+ addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_vertex"), desc, (SwitchType)type, true, switchBody).release());
+ addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_fragment"), desc, (SwitchType)type, false, switchBody).release());
+ }
+}
+
+void ShaderSwitchTests::init (void)
+{
+ // Expected swizzles:
+ // 0: xyz
+ // 1: wzy
+ // 2: yzw
+ // 3: zyx
+
+ makeSwitchCases("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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;"
+ << "}");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createSwitchTests (tcu::TestContext& testCtx)
+{
+ return new ShaderSwitchTests(testCtx);
+}
+
+} // sr
+} // vkt
--- /dev/null
+#ifndef _VKTSHADERRENDERSWITCHTESTS_HPP
+#define _VKTSHADERRENDERSWITCHTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Shader switch statement tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup* createSwitchTests (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRENDERSWITCHTESTS_HPP
#include "vktRenderPassTests.hpp"
#include "vktMemoryTests.hpp"
#include "vktShaderRenderDiscardTests.hpp"
+#include "vktShaderRenderIndexingTests.hpp"
+#include "vktShaderRenderLoopTests.hpp"
+#include "vktShaderRenderMatrixTests.hpp"
+#include "vktShaderRenderOperatorTests.hpp"
+#include "vktShaderRenderReturnTests.hpp"
+#include "vktShaderRenderStructTests.hpp"
+#include "vktShaderRenderSwitchTests.hpp"
#include <vector>
#include <sstream>
std::string("vulkan/glsl/es310/") + s_es310Tests[ndx].name + ".test").release());
// ShaderRenderCase-based tests
- glslTests->addChild(sr::createDiscardTests(testCtx));
+ glslTests->addChild(sr::createDiscardTests (testCtx));
+ glslTests->addChild(sr::createIndexingTests (testCtx));
+ glslTests->addChild(sr::createLoopTests (testCtx));
+ glslTests->addChild(sr::createMatrixTests (testCtx));
+ glslTests->addChild(sr::createOperatorTests (testCtx));
+ glslTests->addChild(sr::createReturnTests (testCtx));
+ glslTests->addChild(sr::createStructTests (testCtx));
+ glslTests->addChild(sr::createSwitchTests (testCtx));
return glslTests.release();
}