Shader Render: add multiple tests
authorPeter Gal <pgal.u-szeged@partner.samsung.com>
Wed, 9 Dec 2015 18:41:58 +0000 (19:41 +0100)
committerPeter Gal <pgal.u-szeged@partner.samsung.com>
Wed, 9 Dec 2015 18:49:02 +0000 (19:49 +0100)
* Indexing tests
* Loop tests
* Matrix tests
* Operator tests
* Return tests
* Struct tests
* Switch tests

17 files changed:
external/vulkancts/modules/vulkan/shaderrender/CMakeLists.txt
external/vulkancts/modules/vulkan/shaderrender/vktShaderRender.hpp
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp

index 83ae801..cbf2cb9 100644 (file)
@@ -7,6 +7,20 @@ set(DEQP_VK_SHADERRENDER_SRCS
        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
index 266d107..6df46d9 100644 (file)
@@ -55,6 +55,21 @@ namespace vkt
 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;
 
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.cpp
new file mode 100644 (file)
index 0000000..c5cd4bb
--- /dev/null
@@ -0,0 +1,1276 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderIndexingTests.hpp
new file mode 100644 (file)
index 0000000..04c6319
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.cpp
new file mode 100644 (file)
index 0000000..d214eba
--- /dev/null
@@ -0,0 +1,1389 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderLoopTests.hpp
new file mode 100644 (file)
index 0000000..7fc08b6
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.cpp
new file mode 100644 (file)
index 0000000..dba861e
--- /dev/null
@@ -0,0 +1,2180 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.hpp
new file mode 100644 (file)
index 0000000..368cd83
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.cpp
new file mode 100644 (file)
index 0000000..21ddb48
--- /dev/null
@@ -0,0 +1,2165 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderOperatorTests.hpp
new file mode 100644 (file)
index 0000000..1fdf715
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.cpp
new file mode 100644 (file)
index 0000000..9174e03
--- /dev/null
@@ -0,0 +1,533 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderReturnTests.hpp
new file mode 100644 (file)
index 0000000..1e4df36
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.cpp
new file mode 100644 (file)
index 0000000..9d6b5c9
--- /dev/null
@@ -0,0 +1,2143 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderStructTests.hpp
new file mode 100644 (file)
index 0000000..a2d3f24
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.cpp
new file mode 100644 (file)
index 0000000..eb56d42
--- /dev/null
@@ -0,0 +1,509 @@
+/*------------------------------------------------------------------------
+ * 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
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderSwitchTests.hpp
new file mode 100644 (file)
index 0000000..8845681
--- /dev/null
@@ -0,0 +1,51 @@
+#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
index 9cde825..22547bc 100644 (file)
 #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>
@@ -262,7 +269,14 @@ tcu::TestCaseGroup* createGlslTests (tcu::TestContext& testCtx)
                                                                                                         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();
 }