Add Uniform Buffer Object tests
authorPeter Gal <pgal.u-szeged@partner.samsung.com>
Tue, 17 Nov 2015 15:32:43 +0000 (16:32 +0100)
committerGabor Abraham <gabraham.u-szeged@partner.samsung.com>
Tue, 15 Dec 2015 12:07:48 +0000 (13:07 +0100)
external/vulkancts/modules/vulkan/CMakeLists.txt
external/vulkancts/modules/vulkan/ubo/CMakeLists.txt [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp

index 919ef4b..8d75651 100644 (file)
@@ -7,6 +7,7 @@ add_subdirectory(spirv_assembly)
 add_subdirectory(shaderrender)
 add_subdirectory(shaderexecutor)
 add_subdirectory(memory)
+add_subdirectory(ubo)
 
 include_directories(
        api
@@ -16,6 +17,7 @@ include_directories(
        shaderrender
        shaderexecutor
        memory
+       ubo
        )
 
 set(DEQP_VK_COMMON_SRCS
@@ -44,6 +46,7 @@ set(DEQP_VK_COMMON_LIBS
        deqp-vk-shaderrender
        deqp-vk-shaderexecutor
        deqp-vk-memory
+       deqp-vk-ubo
        )
 
 if (DE_OS_IS_WIN32 OR DE_OS_IS_UNIX OR DE_OS_IS_OSX)
diff --git a/external/vulkancts/modules/vulkan/ubo/CMakeLists.txt b/external/vulkancts/modules/vulkan/ubo/CMakeLists.txt
new file mode 100644 (file)
index 0000000..38322db
--- /dev/null
@@ -0,0 +1,20 @@
+include_directories(
+       ..
+)
+
+set(DEQP_VK_UBO_SRCS
+       vktUniformBlockCase.cpp
+       vktUniformBlockCase.hpp
+       vktRandomUniformBlockCase.cpp
+       vktRandomUniformBlockCase.hpp
+       vktUniformBlockTests.cpp
+       vktUniformBlockTests.hpp
+)
+
+set(DEQP_VK_UBO_LIBS
+       tcutil
+       vkutil
+)
+
+add_library(deqp-vk-ubo STATIC ${DEQP_VK_UBO_SRCS})
+target_link_libraries(deqp-vk-ubo ${DEQP_VK_UBO_LIBS})
diff --git a/external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.cpp b/external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.cpp
new file mode 100644 (file)
index 0000000..a58524a
--- /dev/null
@@ -0,0 +1,255 @@
+/*------------------------------------------------------------------------
+ * 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 Random uniform block layout case.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktRandomUniformBlockCase.hpp"
+#include "deRandom.hpp"
+
+namespace vkt
+{
+namespace ubo
+{
+
+namespace
+{
+
+static std::string genName (char first, char last, int ndx)
+{
+       std::string     str                     = "";
+       int                     alphabetLen     = last - first + 1;
+
+       while (ndx > alphabetLen)
+       {
+               str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
+               ndx = (ndx - 1) / alphabetLen;
+       }
+
+       str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
+
+       return str;
+}
+
+} // anonymous
+
+RandomUniformBlockCase::RandomUniformBlockCase (tcu::TestContext&      testCtx,
+                                                                                               const std::string&      name,
+                                                                                               const std::string&      description,
+                                                                                               BufferMode                      bufferMode,
+                                                                                               deUint32                        features,
+                                                                                               deUint32                        seed)
+       : UniformBlockCase              (testCtx, name, description, bufferMode)
+       , m_features                    (features)
+       , m_maxVertexBlocks             ((features & FEATURE_VERTEX_BLOCKS)             ? 4 : 0)
+       , m_maxFragmentBlocks   ((features & FEATURE_FRAGMENT_BLOCKS)   ? 4 : 0)
+       , m_maxSharedBlocks             ((features & FEATURE_SHARED_BLOCKS)             ? 4 : 0)
+       , m_maxInstances                ((features & FEATURE_INSTANCE_ARRAYS)   ? 3 : 0)
+       , m_maxArrayLength              ((features & FEATURE_ARRAYS)                    ? 8 : 0)
+       , m_maxStructDepth              ((features & FEATURE_STRUCTS)                   ? 2 : 0)
+       , m_maxBlockMembers             (5)
+       , m_maxStructMembers    (4)
+       , m_seed                                (seed)
+       , m_blockNdx                    (1)
+       , m_uniformNdx                  (1)
+       , m_structNdx                   (1)
+{
+       de::Random rnd(m_seed);
+
+       int numShared           = m_maxSharedBlocks                             > 0     ? rnd.getInt(1, m_maxSharedBlocks)                              : 0;
+       int numVtxBlocks        = m_maxVertexBlocks-numShared   > 0     ? rnd.getInt(1, m_maxVertexBlocks - numShared)  : 0;
+       int     numFragBlocks   = m_maxFragmentBlocks-numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared): 0;
+
+       for (int ndx = 0; ndx < numShared; ndx++)
+               generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
+
+       for (int ndx = 0; ndx < numVtxBlocks; ndx++)
+               generateBlock(rnd, DECLARE_VERTEX);
+
+       for (int ndx = 0; ndx < numFragBlocks; ndx++)
+               generateBlock(rnd, DECLARE_FRAGMENT);
+
+       init();
+}
+
+void RandomUniformBlockCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
+{
+       DE_ASSERT(m_blockNdx <= 'z' - 'a');
+
+       const float             instanceArrayWeight     = 0.3f;
+       UniformBlock&   block                           = m_interface.allocBlock(std::string("Block") + (char)('A' + m_blockNdx));
+       int                             numInstances            = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
+       int                             numUniforms                     = rnd.getInt(1, m_maxBlockMembers);
+
+       if (numInstances > 0)
+               block.setArraySize(numInstances);
+
+       if (numInstances > 0 || rnd.getBool())
+               block.setInstanceName(std::string("block") + (char)('A' + m_blockNdx));
+
+       // Layout flag candidates.
+       std::vector<deUint32> layoutFlagCandidates;
+       layoutFlagCandidates.push_back(0);
+
+       if (m_features & FEATURE_PACKED_LAYOUT)
+               layoutFlagCandidates.push_back(LAYOUT_SHARED);
+       if ((m_features & FEATURE_SHARED_LAYOUT) && ((layoutFlags & DECLARE_BOTH) != DECLARE_BOTH))
+               layoutFlagCandidates.push_back(LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage.
+       if (m_features & FEATURE_STD140_LAYOUT)
+               layoutFlagCandidates.push_back(LAYOUT_STD140);
+
+       layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
+
+       if (m_features & FEATURE_MATRIX_LAYOUT)
+       {
+               static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
+               layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
+       }
+
+       block.setFlags(layoutFlags);
+
+       for (int ndx = 0; ndx < numUniforms; ndx++)
+               generateUniform(rnd, block);
+
+       m_blockNdx += 1;
+}
+
+void RandomUniformBlockCase::generateUniform (de::Random& rnd, UniformBlock& block)
+{
+       const float             unusedVtxWeight         = 0.15f;
+       const float             unusedFragWeight        = 0.15f;
+       bool                    unusedOk                        = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
+       deUint32                flags                           = 0;
+       std::string             name                            = genName('a', 'z', m_uniformNdx);
+       VarType                 type                            = generateType(rnd, 0, true);
+
+       flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight)         ? UNUSED_VERTEX         : 0;
+       flags |= (unusedOk && rnd.getFloat() < unusedFragWeight)        ? UNUSED_FRAGMENT       : 0;
+
+       block.addUniform(Uniform(name, type, flags));
+
+       m_uniformNdx += 1;
+}
+
+VarType RandomUniformBlockCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk)
+{
+       const float structWeight        = 0.1f;
+       const float arrayWeight         = 0.1f;
+
+       if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
+       {
+               const float                             unusedVtxWeight         = 0.15f;
+               const float                             unusedFragWeight        = 0.15f;
+               bool                                    unusedOk                        = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
+               std::vector<VarType>    memberTypes;
+               int                                             numMembers = rnd.getInt(1, m_maxStructMembers);
+
+               // Generate members first so nested struct declarations are in correct order.
+               for (int ndx = 0; ndx < numMembers; ndx++)
+                       memberTypes.push_back(generateType(rnd, typeDepth+1, true));
+
+               StructType& structType = m_interface.allocStruct(std::string("s") + genName('A', 'Z', m_structNdx));
+               m_structNdx += 1;
+
+               DE_ASSERT(numMembers <= 'Z' - 'A');
+               for (int ndx = 0; ndx < numMembers; ndx++)
+               {
+                       deUint32 flags = 0;
+
+                       flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight)         ? UNUSED_VERTEX         : 0;
+                       flags |= (unusedOk && rnd.getFloat() < unusedFragWeight)        ? UNUSED_FRAGMENT       : 0;
+
+                       structType.addMember(std::string("m") + (char)('A' + ndx), memberTypes[ndx], flags);
+               }
+
+               return VarType(&structType);
+       }
+       else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
+       {
+               const bool      arraysOfArraysOk        = (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
+               const int       arrayLength                     = rnd.getInt(1, m_maxArrayLength);
+               VarType         elementType                     = generateType(rnd, typeDepth, arraysOfArraysOk);
+               return VarType(elementType, arrayLength);
+       }
+       else
+       {
+               std::vector<glu::DataType> typeCandidates;
+
+               typeCandidates.push_back(glu::TYPE_FLOAT);
+               typeCandidates.push_back(glu::TYPE_INT);
+               typeCandidates.push_back(glu::TYPE_UINT);
+               typeCandidates.push_back(glu::TYPE_BOOL);
+
+               if (m_features & FEATURE_VECTORS)
+               {
+                       typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
+                       typeCandidates.push_back(glu::TYPE_INT_VEC2);
+                       typeCandidates.push_back(glu::TYPE_INT_VEC3);
+                       typeCandidates.push_back(glu::TYPE_INT_VEC4);
+                       typeCandidates.push_back(glu::TYPE_UINT_VEC2);
+                       typeCandidates.push_back(glu::TYPE_UINT_VEC3);
+                       typeCandidates.push_back(glu::TYPE_UINT_VEC4);
+                       typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
+                       typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
+                       typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
+               }
+
+               if (m_features & FEATURE_MATRICES)
+               {
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
+                       typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
+               }
+
+               glu::DataType   type    = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
+               deUint32                flags   = 0;
+
+               if (!glu::isDataTypeBoolOrBVec(type))
+               {
+                       // Precision.
+                       static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
+                       flags |= rnd.choose<deUint32>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
+               }
+
+               return VarType(type, flags);
+       }
+}
+
+} // ubo
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.hpp b/external/vulkancts/modules/vulkan/ubo/vktRandomUniformBlockCase.hpp
new file mode 100644 (file)
index 0000000..bc424b4
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef _VKTRANDOMUNIFORMBLOCKCASE_HPP
+#define _VKTRANDOMUNIFORMBLOCKCASE_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 Random uniform block layout case.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktUniformBlockCase.hpp"
+
+namespace de
+{
+class Random;
+} // de
+
+namespace vkt
+{
+namespace ubo
+{
+
+enum FeatureBits
+{
+       FEATURE_VECTORS                         = (1<<0),
+       FEATURE_MATRICES                        = (1<<1),
+       FEATURE_ARRAYS                          = (1<<2),
+       FEATURE_STRUCTS                         = (1<<3),
+       FEATURE_NESTED_STRUCTS          = (1<<4),
+       FEATURE_INSTANCE_ARRAYS         = (1<<5),
+       FEATURE_VERTEX_BLOCKS           = (1<<6),
+       FEATURE_FRAGMENT_BLOCKS         = (1<<7),
+       FEATURE_SHARED_BLOCKS           = (1<<8),
+       FEATURE_UNUSED_UNIFORMS         = (1<<9),
+       FEATURE_UNUSED_MEMBERS          = (1<<10),
+       FEATURE_PACKED_LAYOUT           = (1<<12),
+       FEATURE_SHARED_LAYOUT           = (1<<13),
+       FEATURE_STD140_LAYOUT           = (1<<14),
+       FEATURE_MATRIX_LAYOUT           = (1<<15),      //!< Matrix layout flags.
+       FEATURE_ARRAYS_OF_ARRAYS        = (1<<16)
+};
+
+class RandomUniformBlockCase : public UniformBlockCase
+{
+public:
+                                                       RandomUniformBlockCase          (tcu::TestContext&              testCtx,
+                                                                                                                const std::string&             name,
+                                                                                                                const std::string&             description,
+                                                                                                                BufferMode                             bufferMode,
+                                                                                                                deUint32                               features,
+                                                                                                                deUint32                               seed);
+
+private:
+       void                                    generateBlock                           (de::Random& rnd, deUint32 layoutFlags);
+       void                                    generateUniform                         (de::Random& rnd, UniformBlock& block);
+       VarType                                 generateType                            (de::Random& rnd, int typeDepth, bool arrayOk);
+
+       const deUint32                  m_features;
+       const int                               m_maxVertexBlocks;
+       const int                               m_maxFragmentBlocks;
+       const int                               m_maxSharedBlocks;
+       const int                               m_maxInstances;
+       const int                               m_maxArrayLength;
+       const int                               m_maxStructDepth;
+       const int                               m_maxBlockMembers;
+       const int                               m_maxStructMembers;
+       const deUint32                  m_seed;
+
+       int                                             m_blockNdx;
+       int                                             m_uniformNdx;
+       int                                             m_structNdx;
+};
+
+} // ubo
+} // vkt
+
+#endif // _VKTRANDOMUNIFORMBLOCKCASE_HPP
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp
new file mode 100644 (file)
index 0000000..5ae2c6b
--- /dev/null
@@ -0,0 +1,1991 @@
+/*------------------------------------------------------------------------
+ * 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 Uniform block case.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktUniformBlockCase.hpp"
+
+#include "vkPrograms.hpp"
+
+#include "gluVarType.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuSurface.hpp"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+
+#include "tcuTextureUtil.hpp"
+#include "deSharedPtr.hpp"
+
+#include "vkMemUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkBuilderUtil.hpp"
+
+#include <map>
+#include <set>
+
+namespace vkt
+{
+namespace ubo
+{
+
+using namespace vk;
+
+// VarType implementation.
+
+VarType::VarType (void)
+       : m_type        (TYPE_LAST)
+       , m_flags       (0)
+{
+}
+
+VarType::VarType (const VarType& other)
+       : m_type        (TYPE_LAST)
+       , m_flags       (0)
+{
+       *this = other;
+}
+
+VarType::VarType (glu::DataType basicType, deUint32 flags)
+       : m_type        (TYPE_BASIC)
+       , m_flags       (flags)
+{
+       m_data.basicType = basicType;
+}
+
+VarType::VarType (const VarType& elementType, int arraySize)
+       : m_type        (TYPE_ARRAY)
+       , m_flags       (0)
+{
+       m_data.array.size                       = arraySize;
+       m_data.array.elementType        = new VarType(elementType);
+}
+
+VarType::VarType (const StructType* structPtr)
+       : m_type        (TYPE_STRUCT)
+       , m_flags       (0)
+{
+       m_data.structPtr = structPtr;
+}
+
+VarType::~VarType (void)
+{
+       if (m_type == TYPE_ARRAY)
+               delete m_data.array.elementType;
+}
+
+VarType& VarType::operator= (const VarType& other)
+{
+       if (this == &other)
+               return *this; // Self-assignment.
+
+       if (m_type == TYPE_ARRAY)
+               delete m_data.array.elementType;
+
+       m_type  = other.m_type;
+       m_flags = other.m_flags;
+       m_data  = Data();
+
+       if (m_type == TYPE_ARRAY)
+       {
+               m_data.array.elementType        = new VarType(*other.m_data.array.elementType);
+               m_data.array.size                       = other.m_data.array.size;
+       }
+       else
+               m_data = other.m_data;
+
+       return *this;
+}
+
+// StructType implementation.
+
+void StructType::addMember (const std::string& name, const VarType& type, deUint32 flags)
+{
+       m_members.push_back(StructMember(name, type, flags));
+}
+
+// Uniform implementation.
+
+Uniform::Uniform (const std::string& name, const VarType& type, deUint32 flags)
+       : m_name        (name)
+       , m_type        (type)
+       , m_flags       (flags)
+{
+}
+
+// UniformBlock implementation.
+
+UniformBlock::UniformBlock (const std::string& blockName)
+       : m_blockName   (blockName)
+       , m_arraySize   (0)
+       , m_flags               (0)
+{
+}
+
+std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
+{
+       stream << entry.name << " { name = " << entry.name
+                  << ", size = " << entry.size
+                  << ", activeUniformIndices = [";
+
+       for (std::vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
+       {
+               if (i != entry.activeUniformIndices.begin())
+                       stream << ", ";
+               stream << *i;
+       }
+
+       stream << "] }";
+       return stream;
+}
+
+std::ostream& operator<< (std::ostream& stream, const UniformLayoutEntry& entry)
+{
+       stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
+                  << ", size = " << entry.size
+                  << ", blockNdx = " << entry.blockNdx
+                  << ", offset = " << entry.offset
+                  << ", arrayStride = " << entry.arrayStride
+                  << ", matrixStride = " << entry.matrixStride
+                  << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
+                  << " }";
+       return stream;
+}
+
+int UniformLayout::getUniformIndex (const std::string& name) const
+{
+       for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
+       {
+               if (uniforms[ndx].name == name)
+                       return ndx;
+       }
+
+       return -1;
+}
+
+int UniformLayout::getBlockIndex (const std::string& name) const
+{
+       for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
+       {
+               if (blocks[ndx].name == name)
+                       return ndx;
+       }
+
+       return -1;
+}
+
+// ShaderInterface implementation.
+
+ShaderInterface::ShaderInterface (void)
+{
+}
+
+ShaderInterface::~ShaderInterface (void)
+{
+}
+
+StructType& ShaderInterface::allocStruct (const std::string& name)
+{
+       m_structs.push_back(StructTypeSP(new StructType(name)));
+       return *m_structs.back();
+}
+
+struct StructNameEquals
+{
+       std::string name;
+
+       StructNameEquals (const std::string& name_) : name(name_) {}
+
+       bool operator() (const StructTypeSP type) const
+       {
+               return type->hasTypeName() && name == type->getTypeName();
+       }
+};
+
+void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
+{
+       for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
+       {
+               if ((*i)->hasTypeName())
+                       structs.push_back((*i).get());
+       }
+}
+
+UniformBlock& ShaderInterface::allocBlock (const std::string& name)
+{
+       m_uniformBlocks.push_back(UniformBlockSP(new UniformBlock(name)));
+       return *m_uniformBlocks.back();
+}
+
+namespace // Utilities
+{
+
+struct PrecisionFlagsFmt
+{
+       deUint32 flags;
+       PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const PrecisionFlagsFmt& fmt)
+{
+       // Precision.
+       DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH)) <= 1);
+       str << (fmt.flags & PRECISION_LOW               ? "lowp"        :
+                       fmt.flags & PRECISION_MEDIUM    ? "mediump"     :
+                       fmt.flags & PRECISION_HIGH              ? "highp"       : "");
+       return str;
+}
+
+struct LayoutFlagsFmt
+{
+       deUint32 flags;
+       LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
+{
+       static const struct
+       {
+               deUint32        bit;
+               const char*     token;
+       } bitDesc[] =
+       {
+               { LAYOUT_SHARED,                "shared"                },
+               { LAYOUT_PACKED,                "packed"                },
+               { LAYOUT_STD140,                "std140"                },
+               { LAYOUT_ROW_MAJOR,             "row_major"             },
+               { LAYOUT_COLUMN_MAJOR,  "column_major"  }
+       };
+
+       deUint32 remBits = fmt.flags;
+       for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
+       {
+               if (remBits & bitDesc[descNdx].bit)
+               {
+                       if (remBits != fmt.flags)
+                               str << ", ";
+                       str << bitDesc[descNdx].token;
+                       remBits &= ~bitDesc[descNdx].bit;
+               }
+       }
+       DE_ASSERT(remBits == 0);
+       return str;
+}
+
+// Layout computation.
+
+int getDataTypeByteSize (glu::DataType type)
+{
+       return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
+}
+
+int getDataTypeByteAlignment (glu::DataType type)
+{
+       switch (type)
+       {
+               case glu::TYPE_FLOAT:
+               case glu::TYPE_INT:
+               case glu::TYPE_UINT:
+               case glu::TYPE_BOOL:            return 1*(int)sizeof(deUint32);
+
+               case glu::TYPE_FLOAT_VEC2:
+               case glu::TYPE_INT_VEC2:
+               case glu::TYPE_UINT_VEC2:
+               case glu::TYPE_BOOL_VEC2:       return 2*(int)sizeof(deUint32);
+
+               case glu::TYPE_FLOAT_VEC3:
+               case glu::TYPE_INT_VEC3:
+               case glu::TYPE_UINT_VEC3:
+               case glu::TYPE_BOOL_VEC3:       // Fall-through to vec4
+
+               case glu::TYPE_FLOAT_VEC4:
+               case glu::TYPE_INT_VEC4:
+               case glu::TYPE_UINT_VEC4:
+               case glu::TYPE_BOOL_VEC4:       return 4*(int)sizeof(deUint32);
+
+               default:
+                       DE_ASSERT(false);
+                       return 0;
+       }
+}
+
+int getDataTypeArrayStride (glu::DataType type)
+{
+       DE_ASSERT(!glu::isDataTypeMatrix(type));
+
+       const int baseStride    = getDataTypeByteSize(type);
+       const int vec4Alignment = (int)sizeof(deUint32)*4;
+
+       DE_ASSERT(baseStride <= vec4Alignment);
+       return de::max(baseStride, vec4Alignment); // Really? See rule 4.
+}
+
+static inline int deRoundUp32 (int a, int b)
+{
+       int d = a/b;
+       return d*b == a ? a : (d+1)*b;
+}
+
+int computeStd140BaseAlignment (const VarType& type)
+{
+       const int vec4Alignment = (int)sizeof(deUint32)*4;
+
+       if (type.isBasicType())
+       {
+               glu::DataType basicType = type.getBasicType();
+
+               if (glu::isDataTypeMatrix(basicType))
+               {
+                       bool    isRowMajor      = !!(type.getFlags() & LAYOUT_ROW_MAJOR);
+                       int             vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
+                                                                                        : glu::getDataTypeMatrixNumRows(basicType);
+
+                       return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
+               }
+               else
+                       return getDataTypeByteAlignment(basicType);
+       }
+       else if (type.isArrayType())
+       {
+               int elemAlignment = computeStd140BaseAlignment(type.getElementType());
+
+               // Round up to alignment of vec4
+               return deRoundUp32(elemAlignment, vec4Alignment);
+       }
+       else
+       {
+               DE_ASSERT(type.isStructType());
+
+               int maxBaseAlignment = 0;
+
+               for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
+                       maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType()));
+
+               return deRoundUp32(maxBaseAlignment, vec4Alignment);
+       }
+}
+
+inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
+{
+       const deUint32  packingMask             = LAYOUT_PACKED|LAYOUT_SHARED|LAYOUT_STD140;
+       const deUint32  matrixMask              = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
+
+       deUint32 mergedFlags = 0;
+
+       mergedFlags |= ((newFlags & packingMask)        ? newFlags : prevFlags) & packingMask;
+       mergedFlags |= ((newFlags & matrixMask)         ? newFlags : prevFlags) & matrixMask;
+
+       return mergedFlags;
+}
+
+void computeStd140Layout (UniformLayout& layout, int& curOffset, int curBlockNdx, const std::string& curPrefix, const VarType& type, deUint32 layoutFlags)
+{
+       int baseAlignment = computeStd140BaseAlignment(type);
+
+       curOffset = deAlign32(curOffset, baseAlignment);
+
+       if (type.isBasicType())
+       {
+               glu::DataType           basicType       = type.getBasicType();
+               UniformLayoutEntry      entry;
+
+               entry.name                      = curPrefix;
+               entry.type                      = basicType;
+               entry.size                      = 1;
+               entry.arrayStride       = 0;
+               entry.matrixStride      = 0;
+               entry.blockNdx          = curBlockNdx;
+
+               if (glu::isDataTypeMatrix(basicType))
+               {
+                       // Array of vectors as specified in rules 5 & 7.
+                       bool    isRowMajor      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
+                       int             vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
+                                                                                        : glu::getDataTypeMatrixNumRows(basicType);
+                       int             numVecs         = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
+                                                                                        : glu::getDataTypeMatrixNumColumns(basicType);
+                       int             stride          = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
+
+                       entry.offset            = curOffset;
+                       entry.matrixStride      = stride;
+                       entry.isRowMajor        = isRowMajor;
+
+                       curOffset += numVecs*stride;
+               }
+               else
+               {
+                       // Scalar or vector.
+                       entry.offset = curOffset;
+
+                       curOffset += getDataTypeByteSize(basicType);
+               }
+
+               layout.uniforms.push_back(entry);
+       }
+       else if (type.isArrayType())
+       {
+               const VarType&  elemType        = type.getElementType();
+
+               if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
+               {
+                       // Array of scalars or vectors.
+                       glu::DataType           elemBasicType   = elemType.getBasicType();
+                       UniformLayoutEntry      entry;
+                       int                                     stride                  = getDataTypeArrayStride(elemBasicType);
+
+                       entry.name                      = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
+                       entry.type                      = elemBasicType;
+                       entry.blockNdx          = curBlockNdx;
+                       entry.offset            = curOffset;
+                       entry.size                      = type.getArraySize();
+                       entry.arrayStride       = stride;
+                       entry.matrixStride      = 0;
+
+                       curOffset += stride*type.getArraySize();
+
+                       layout.uniforms.push_back(entry);
+               }
+               else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
+               {
+                       // Array of matrices.
+                       glu::DataType           elemBasicType   = elemType.getBasicType();
+                       bool                            isRowMajor              = !!(layoutFlags & LAYOUT_ROW_MAJOR);
+                       int                                     vecSize                 = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
+                                                                                                                        : glu::getDataTypeMatrixNumRows(elemBasicType);
+                       int                                     numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
+                                                                                                                        : glu::getDataTypeMatrixNumColumns(elemBasicType);
+                       int                                     stride                  = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
+                       UniformLayoutEntry      entry;
+
+                       entry.name                      = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
+                       entry.type                      = elemBasicType;
+                       entry.blockNdx          = curBlockNdx;
+                       entry.offset            = curOffset;
+                       entry.size                      = type.getArraySize();
+                       entry.arrayStride       = stride*numVecs;
+                       entry.matrixStride      = stride;
+                       entry.isRowMajor        = isRowMajor;
+
+                       curOffset += numVecs*type.getArraySize()*stride;
+
+                       layout.uniforms.push_back(entry);
+               }
+               else
+               {
+                       DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
+
+                       for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
+                               computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
+               }
+       }
+       else
+       {
+               DE_ASSERT(type.isStructType());
+
+               for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
+                       computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
+
+               curOffset = deAlign32(curOffset, baseAlignment);
+       }
+}
+
+void computeStd140Layout (UniformLayout& layout, const ShaderInterface& interface)
+{
+       int numUniformBlocks = interface.getNumUniformBlocks();
+
+       for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
+       {
+               const UniformBlock&     block                   = interface.getUniformBlock(blockNdx);
+               bool                            hasInstanceName = block.hasInstanceName();
+               std::string                     blockPrefix             = hasInstanceName ? (block.getBlockName() + ".") : "";
+               int                                     curOffset               = 0;
+               int                                     activeBlockNdx  = (int)layout.blocks.size();
+               int                                     firstUniformNdx = (int)layout.uniforms.size();
+
+               for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
+               {
+                       const Uniform& uniform = *uniformIter;
+                       computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(), mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
+               }
+
+               int     uniformIndicesEnd       = (int)layout.uniforms.size();
+               int     blockSize                       = curOffset;
+               int     numInstances            = block.isArray() ? block.getArraySize() : 1;
+
+               // Create block layout entries for each instance.
+               for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
+               {
+                       // Allocate entry for instance.
+                       layout.blocks.push_back(BlockLayoutEntry());
+                       BlockLayoutEntry& blockEntry = layout.blocks.back();
+
+                       blockEntry.name = block.getBlockName();
+                       blockEntry.size = blockSize;
+                       blockEntry.bindingNdx = blockNdx;
+                       blockEntry.instanceNdx = instanceNdx;
+
+                       // Compute active uniform set for block.
+                       for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
+                               blockEntry.activeUniformIndices.push_back(uniformNdx);
+
+                       if (block.isArray())
+                               blockEntry.name += "[" + de::toString(instanceNdx) + "]";
+               }
+       }
+}
+
+// Value generator.
+
+void generateValue (const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd)
+{
+       glu::DataType   scalarType              = glu::getDataTypeScalarType(entry.type);
+       int                             scalarSize              = glu::getDataTypeScalarSize(entry.type);
+       bool                    isMatrix                = glu::isDataTypeMatrix(entry.type);
+       int                             numVecs                 = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
+       int                             vecSize                 = scalarSize / numVecs;
+       bool                    isArray                 = entry.size > 1;
+       const int               compSize                = sizeof(deUint32);
+
+       DE_ASSERT(scalarSize%numVecs == 0);
+
+       for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
+       {
+               deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
+
+               for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
+               {
+                       deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
+
+                       for (int compNdx = 0; compNdx < vecSize; compNdx++)
+                       {
+                               deUint8* compPtr = vecPtr + compSize*compNdx;
+
+                               switch (scalarType)
+                               {
+                                       case glu::TYPE_FLOAT:   *((float*)compPtr)              = (float)rnd.getInt(-9, 9);                                             break;
+                                       case glu::TYPE_INT:             *((int*)compPtr)                = rnd.getInt(-9, 9);                                                    break;
+                                       case glu::TYPE_UINT:    *((deUint32*)compPtr)   = (deUint32)rnd.getInt(0, 9);                                   break;
+                                       // \note Random bit pattern is used for true values. Spec states that all non-zero values are
+                                       //       interpreted as true but some implementations fail this.
+                                       case glu::TYPE_BOOL:    *((deUint32*)compPtr)   = rnd.getBool() ? rnd.getUint32()|1u : 0u;              break;
+                                       default:
+                                               DE_ASSERT(false);
+                               }
+                       }
+               }
+       }
+}
+
+void generateValues (const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
+{
+       de::Random      rnd                     (seed);
+       int                     numBlocks       = (int)layout.blocks.size();
+
+       for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+       {
+               void*   basePtr         = blockPointers.find(blockNdx)->second;
+               int             numEntries      = (int)layout.blocks[blockNdx].activeUniformIndices.size();
+
+               for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
+               {
+                       const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
+                       generateValue(entry, basePtr, rnd);
+               }
+       }
+}
+
+// Shader generator.
+
+const char* getCompareFuncForType (glu::DataType type)
+{
+       switch (type)
+       {
+               case glu::TYPE_FLOAT:                   return "mediump float compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n";
+               case glu::TYPE_FLOAT_VEC2:              return "mediump float compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n";
+               case glu::TYPE_FLOAT_VEC3:              return "mediump float compare_vec3     (highp vec3 a, highp vec3 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n";
+               case glu::TYPE_FLOAT_VEC4:              return "mediump float compare_vec4     (highp vec4 a, highp vec4 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n";
+               case glu::TYPE_FLOAT_MAT2:              return "mediump float compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }\n";
+               case glu::TYPE_FLOAT_MAT2X3:    return "mediump float compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }\n";
+               case glu::TYPE_FLOAT_MAT2X4:    return "mediump float compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }\n";
+               case glu::TYPE_FLOAT_MAT3X2:    return "mediump float compare_mat3x2   (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n";
+               case glu::TYPE_FLOAT_MAT3:              return "mediump float compare_mat3     (highp mat3 a, highp mat3 b)    { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n";
+               case glu::TYPE_FLOAT_MAT3X4:    return "mediump float compare_mat3x4   (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n";
+               case glu::TYPE_FLOAT_MAT4X2:    return "mediump float compare_mat4x2   (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n";
+               case glu::TYPE_FLOAT_MAT4X3:    return "mediump float compare_mat4x3   (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n";
+               case glu::TYPE_FLOAT_MAT4:              return "mediump float compare_mat4     (highp mat4 a, highp mat4 b)    { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n";
+               case glu::TYPE_INT:                             return "mediump float compare_int      (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_INT_VEC2:                return "mediump float compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_INT_VEC3:                return "mediump float compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_INT_VEC4:                return "mediump float compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_UINT:                    return "mediump float compare_uint     (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_UINT_VEC2:               return "mediump float compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_UINT_VEC3:               return "mediump float compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_UINT_VEC4:               return "mediump float compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_BOOL:                    return "mediump float compare_bool     (bool a, bool b)                { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_BOOL_VEC2:               return "mediump float compare_bvec2    (bvec2 a, bvec2 b)              { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_BOOL_VEC3:               return "mediump float compare_bvec3    (bvec3 a, bvec3 b)              { return a == b ? 1.0 : 0.0; }\n";
+               case glu::TYPE_BOOL_VEC4:               return "mediump float compare_bvec4    (bvec4 a, bvec4 b)              { return a == b ? 1.0 : 0.0; }\n";
+               default:
+                       DE_ASSERT(false);
+                       return DE_NULL;
+       }
+}
+
+void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
+{
+       switch (basicType)
+       {
+               case glu::TYPE_FLOAT_VEC2:
+               case glu::TYPE_FLOAT_VEC3:
+               case glu::TYPE_FLOAT_VEC4:
+                       compareFuncs.insert(glu::TYPE_FLOAT);
+                       compareFuncs.insert(basicType);
+                       break;
+
+               case glu::TYPE_FLOAT_MAT2:
+               case glu::TYPE_FLOAT_MAT2X3:
+               case glu::TYPE_FLOAT_MAT2X4:
+               case glu::TYPE_FLOAT_MAT3X2:
+               case glu::TYPE_FLOAT_MAT3:
+               case glu::TYPE_FLOAT_MAT3X4:
+               case glu::TYPE_FLOAT_MAT4X2:
+               case glu::TYPE_FLOAT_MAT4X3:
+               case glu::TYPE_FLOAT_MAT4:
+                       compareFuncs.insert(glu::TYPE_FLOAT);
+                       compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
+                       compareFuncs.insert(basicType);
+                       break;
+
+               default:
+                       compareFuncs.insert(basicType);
+                       break;
+       }
+}
+
+void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
+{
+       if (type.isStructType())
+       {
+               for (StructType::ConstIterator iter = type.getStruct().begin(); iter != type.getStruct().end(); ++iter)
+                       collectUniqueBasicTypes(basicTypes, iter->getType());
+       }
+       else if (type.isArrayType())
+               collectUniqueBasicTypes(basicTypes, type.getElementType());
+       else
+       {
+               DE_ASSERT(type.isBasicType());
+               basicTypes.insert(type.getBasicType());
+       }
+}
+
+void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const UniformBlock& uniformBlock)
+{
+       for (UniformBlock::ConstIterator iter = uniformBlock.begin(); iter != uniformBlock.end(); ++iter)
+               collectUniqueBasicTypes(basicTypes, iter->getType());
+}
+
+void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
+{
+       for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
+               collectUniqueBasicTypes(basicTypes, interface.getUniformBlock(ndx));
+}
+
+void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
+{
+       std::set<glu::DataType> types;
+       std::set<glu::DataType> compareFuncs;
+
+       // Collect unique basic types
+       collectUniqueBasicTypes(types, interface);
+
+       // Set of compare functions required
+       for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
+       {
+               getCompareDependencies(compareFuncs, *iter);
+       }
+
+       for (int type = 0; type < glu::TYPE_LAST; ++type)
+       {
+               if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
+                       str << getCompareFuncForType(glu::DataType(type));
+       }
+}
+
+struct Indent
+{
+       int level;
+       Indent (int level_) : level(level_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const Indent& indent)
+{
+       for (int i = 0; i < indent.level; i++)
+               str << "\t";
+       return str;
+}
+
+void           generateDeclaration                     (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints);
+void           generateDeclaration                     (std::ostringstream& src, const Uniform& uniform, int indentLevel);
+void           generateDeclaration                     (std::ostringstream& src, const StructType& structType, int indentLevel);
+
+void           generateLocalDeclaration        (std::ostringstream& src, const StructType& structType, int indentLevel);
+void           generateFullDeclaration         (std::ostringstream& src, const StructType& structType, int indentLevel);
+
+void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
+{
+       DE_ASSERT(structType.hasTypeName());
+       generateFullDeclaration(src, structType, indentLevel);
+       src << ";\n";
+}
+
+void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
+{
+       src << "struct";
+       if (structType.hasTypeName())
+               src << " " << structType.getTypeName();
+       src << "\n" << Indent(indentLevel) << "{\n";
+
+       for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
+       {
+               src << Indent(indentLevel + 1);
+               generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, memberIter->getFlags() & UNUSED_BOTH);
+       }
+
+       src << Indent(indentLevel) << "}";
+}
+
+void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */)
+{
+       src << structType.getTypeName();
+}
+
+void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints)
+{
+       deUint32 flags = type.getFlags();
+
+       if ((flags & LAYOUT_MASK) != 0)
+               src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") ";
+
+       if ((flags & PRECISION_MASK) != 0)
+               src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
+
+       if (type.isBasicType())
+               src << glu::getDataTypeName(type.getBasicType()) << " " << name;
+       else if (type.isArrayType())
+       {
+               std::vector<int>        arraySizes;
+               const VarType*          curType         = &type;
+               while (curType->isArrayType())
+               {
+                       arraySizes.push_back(curType->getArraySize());
+                       curType = &curType->getElementType();
+               }
+
+               if (curType->isBasicType())
+               {
+                       if ((curType->getFlags() & PRECISION_MASK) != 0)
+                               src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " ";
+                       src << glu::getDataTypeName(curType->getBasicType());
+               }
+               else
+               {
+                       DE_ASSERT(curType->isStructType());
+                       generateLocalDeclaration(src, curType->getStruct(), indentLevel+1);
+               }
+
+               src << " " << name;
+
+               for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++)
+                       src << "[" << *sizeIter << "]";
+       }
+       else
+       {
+               generateLocalDeclaration(src, type.getStruct(), indentLevel+1);
+               src << " " << name;
+       }
+
+       src << ";";
+
+       // Print out unused hints.
+       if (unusedHints != 0)
+               src << " // unused in " << (unusedHints == UNUSED_BOTH          ? "both shaders"        :
+                                                                       unusedHints == UNUSED_VERTEX    ? "vertex shader"       :
+                                                                       unusedHints == UNUSED_FRAGMENT  ? "fragment shader" : "???");
+
+       src << "\n";
+}
+
+void generateDeclaration (std::ostringstream& src, const Uniform& uniform, int indentLevel)
+{
+       if ((uniform.getFlags() & LAYOUT_MASK) != 0)
+               src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
+
+       generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH);
+}
+
+void generateDeclaration (std::ostringstream& src, int blockNdx, const UniformBlock& block)
+{
+       src << "layout(set = 0, binding = " << blockNdx;
+       if ((block.getFlags() & LAYOUT_MASK) != 0)
+               src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK);
+       src << ") ";
+
+       src << "uniform " << block.getBlockName();
+       src << "\n{\n";
+
+       for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
+       {
+               src << Indent(1);
+               generateDeclaration(src, *uniformIter, 1 /* indent level */);
+       }
+
+       src << "}";
+
+       if (block.hasInstanceName())
+       {
+               src << " " << block.getInstanceName();
+               if (block.isArray())
+                       src << "[" << block.getArraySize() << "]";
+       }
+       else
+               DE_ASSERT(!block.isArray());
+
+       src << ";\n";
+}
+
+void generateValueSrc (std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx)
+{
+       glu::DataType   scalarType              = glu::getDataTypeScalarType(entry.type);
+       int                             scalarSize              = glu::getDataTypeScalarSize(entry.type);
+       bool                    isArray                 = entry.size > 1;
+       const deUint8*  elemPtr                 = (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
+       const int               compSize                = sizeof(deUint32);
+
+       if (scalarSize > 1)
+               src << glu::getDataTypeName(entry.type) << "(";
+
+       if (glu::isDataTypeMatrix(entry.type))
+       {
+               int     numRows = glu::getDataTypeMatrixNumRows(entry.type);
+               int     numCols = glu::getDataTypeMatrixNumColumns(entry.type);
+
+               DE_ASSERT(scalarType == glu::TYPE_FLOAT);
+
+               // Constructed in column-wise order.
+               for (int colNdx = 0; colNdx < numCols; colNdx++)
+               {
+                       for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
+                       {
+                               const deUint8*  compPtr = elemPtr + (entry.isRowMajor ? (rowNdx * entry.matrixStride + colNdx * compSize)
+                                                                                                                                         : (colNdx * entry.matrixStride + rowNdx * compSize));
+
+                               if (colNdx > 0 || rowNdx > 0)
+                                       src << ", ";
+
+                               src << de::floatToString(*((const float*)compPtr), 1);
+                       }
+               }
+       }
+       else
+       {
+               for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
+               {
+                       const deUint8* compPtr = elemPtr + scalarNdx * compSize;
+
+                       if (scalarNdx > 0)
+                               src << ", ";
+
+                       switch (scalarType)
+                       {
+                               case glu::TYPE_FLOAT:   src << de::floatToString(*((const float*)compPtr), 1);                  break;
+                               case glu::TYPE_INT:             src << *((const int*)compPtr);                                                                  break;
+                               case glu::TYPE_UINT:    src << *((const deUint32*)compPtr) << "u";                                              break;
+                               case glu::TYPE_BOOL:    src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");  break;
+                               default:
+                                       DE_ASSERT(false);
+                       }
+               }
+       }
+
+       if (scalarSize > 1)
+               src << ")";
+}
+
+void generateCompareSrc (std::ostringstream&   src,
+                                                const char*                    resultVar,
+                                                const VarType&                 type,
+                                                const std::string&             srcName,
+                                                const std::string&             apiName,
+                                                const UniformLayout&   layout,
+                                                const void*                    basePtr,
+                                                deUint32                               unusedMask)
+{
+       if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
+       {
+               // Basic type or array of basic types.
+               bool                                            isArray                 = type.isArrayType();
+               glu::DataType                           elementType             = isArray ? type.getElementType().getBasicType() : type.getBasicType();
+               const char*                                     typeName                = glu::getDataTypeName(elementType);
+               std::string                                     fullApiName             = std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
+               int                                                     uniformNdx              = layout.getUniformIndex(fullApiName);
+               const UniformLayoutEntry&       entry                   = layout.uniforms[uniformNdx];
+
+               if (isArray)
+               {
+                       for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
+                       {
+                               src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], ";
+                               generateValueSrc(src, entry, basePtr, elemNdx);
+                               src << ");\n";
+                       }
+               }
+               else
+               {
+                       src << "\tresult *= compare_" << typeName << "(" << srcName << ", ";
+                       generateValueSrc(src, entry, basePtr, 0);
+                       src << ");\n";
+               }
+       }
+       else if (type.isArrayType())
+       {
+               const VarType& elementType = type.getElementType();
+
+               for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
+               {
+                       std::string op = std::string("[") + de::toString(elementNdx) + "]";
+                       std::string elementSrcName = std::string(srcName) + op;
+                       std::string elementApiName = std::string(apiName) + op;
+                       generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, basePtr, unusedMask);
+               }
+       }
+       else
+       {
+               DE_ASSERT(type.isStructType());
+
+               for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
+               {
+                       if (memberIter->getFlags() & unusedMask)
+                               continue; // Skip member.
+
+                       std::string op = std::string(".") + memberIter->getName();
+                       std::string memberSrcName = std::string(srcName) + op;
+                       std::string memberApiName = std::string(apiName) + op;
+                       generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, basePtr, unusedMask);
+               }
+       }
+}
+
+void generateCompareSrc (std::ostringstream& src, const char* resultVar, const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, bool isVertex)
+{
+       deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
+
+       for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
+       {
+               const UniformBlock& block = interface.getUniformBlock(blockNdx);
+
+               if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
+                       continue; // Skip.
+
+               bool                    hasInstanceName = block.hasInstanceName();
+               bool                    isArray                 = block.isArray();
+               int                             numInstances    = isArray ? block.getArraySize() : 1;
+               std::string             apiPrefix               = hasInstanceName ? block.getBlockName() + "." : std::string("");
+
+               DE_ASSERT(!isArray || hasInstanceName);
+
+               for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
+               {
+                       std::string             instancePostfix         = isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string("");
+                       std::string             blockInstanceName       = block.getBlockName() + instancePostfix;
+                       std::string             srcPrefix                       = hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
+                       int                             activeBlockNdx          = layout.getBlockIndex(blockInstanceName);
+                       void*                   basePtr                         = blockPointers.find(activeBlockNdx)->second;
+
+                       for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
+                       {
+                               const Uniform& uniform = *uniformIter;
+
+                               if (uniform.getFlags() & unusedMask)
+                                       continue; // Don't read from that uniform.
+
+                               std::string srcName = srcPrefix + uniform.getName();
+                               std::string apiName = apiPrefix + uniform.getName();
+                               generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, basePtr, unusedMask);
+                       }
+               }
+       }
+}
+
+std::string generateVertexShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers)
+{
+       std::ostringstream src;
+       src << "#version 450\n";
+
+       src << "layout(location = 0) in highp vec4 a_position;\n";
+       src << "layout(location = 0) out mediump float v_vtxResult;\n";
+       src << "\n";
+
+       std::vector<const StructType*> namedStructs;
+       interface.getNamedStructs(namedStructs);
+       for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
+               generateDeclaration(src, **structIter, 0);
+
+       for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
+       {
+               const UniformBlock& block = interface.getUniformBlock(blockNdx);
+               if (block.getFlags() & DECLARE_VERTEX)
+                       generateDeclaration(src, blockNdx, block);
+       }
+
+       // Comparison utilities.
+       src << "\n";
+       generateCompareFuncs(src, interface);
+
+       src << "\n"
+                  "void main (void)\n"
+                  "{\n"
+                  "    gl_Position = a_position;\n"
+                  "    mediump float result = 1.0;\n";
+
+       // Value compare.
+       generateCompareSrc(src, "result", interface, layout, blockPointers, true);
+
+       src << "        v_vtxResult = result;\n"
+                  "}\n";
+
+       return src.str();
+}
+
+std::string generateFragmentShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers)
+{
+       std::ostringstream src;
+       src << "#version 450\n";
+
+       src << "layout(location = 0) in mediump float v_vtxResult;\n";
+       src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+       src << "\n";
+
+       std::vector<const StructType*> namedStructs;
+       interface.getNamedStructs(namedStructs);
+       for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
+               generateDeclaration(src, **structIter, 0);
+
+       for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
+       {
+               const UniformBlock& block = interface.getUniformBlock(blockNdx);
+               if (block.getFlags() & DECLARE_FRAGMENT)
+                       generateDeclaration(src, blockNdx, block);
+       }
+
+       // Comparison utilities.
+       src << "\n";
+       generateCompareFuncs(src, interface);
+
+       src << "\n"
+                  "void main (void)\n"
+                  "{\n"
+                  "    mediump float result = 1.0;\n";
+
+       // Value compare.
+       generateCompareSrc(src, "result", interface, layout, blockPointers, false);
+
+       src << "        dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
+                  "}\n";
+
+       return src.str();
+}
+
+Move<VkBuffer> createBuffer (Context& context, VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
+{
+       const VkDevice                          vkDevice                        = context.getDevice();
+       const DeviceInterface&          vk                                      = context.getDeviceInterface();
+       const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+
+       const VkBufferCreateInfo        bufferInfo                      =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   // VkStructureType              sType;
+               DE_NULL,                                                                // const void*                  pNext;
+               0u,                                                                             // VkBufferCreateFlags  flags;
+               bufferSize,                                                             // VkDeviceSize                 size;
+               usageFlags,                                                             // VkBufferUsageFlags   usage;
+               VK_SHARING_MODE_EXCLUSIVE,                              // VkSharingMode                sharingMode;
+               1u,                                                                             // deUint32                             queueFamilyIndexCount;
+               &queueFamilyIndex                                               // const deUint32*              pQueueFamilyIndices;
+       };
+
+       return vk::createBuffer(vk, vkDevice, &bufferInfo);
+}
+
+Move<vk::VkImage> createImage2D (Context& context, int width, int height, vk::VkFormat format, vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
+{
+       const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+       const vk::VkImageCreateInfo     params                          =
+       {
+               vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,        // VkStructureType                      sType
+               DE_NULL,                                                                        // const void*                          pNext
+               0u,                                                                                     // VkImageCreateFlags           flags
+               vk::VK_IMAGE_TYPE_2D,                                           // VkImageType                          imageType
+               format,                                                                         // VkFormat                                     format
+               { width, height, 1 },                                           // VkExtent3D                           extent
+               1u,                                                                                     // deUint32                                     mipLevels
+               1u,                                                                                     // deUint32                                     arrayLayers
+               VK_SAMPLE_COUNT_1_BIT,                                          // VkSampleCountFlagBits        samples
+               tiling,                                                                         // VkImageTiling                        tiling
+               usageFlags,                                                                     // VkImageUsageFlags            usage
+               vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                        sharingMode
+               1u,                                                                                     // deUint32                                     queueFamilyIndexCount
+               &queueFamilyIndex,                                                      // const deUint32*                      pQueueFamilyIndices
+               vk::VK_IMAGE_LAYOUT_UNDEFINED,                          // VkImageLayout                        initialLayout
+       };
+
+       return vk::createImage(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
+{
+       const vk::DeviceInterface&              vkd             = context.getDeviceInterface();
+       const vk::VkMemoryRequirements  bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
+       de::MovePtr<vk::Allocation>             memory  = context.getDefaultAllocator().allocate(bufReqs, memReqs);
+
+       vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
+
+       return memory;
+}
+
+de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkImage image, vk::MemoryRequirement memReqs)
+{
+       const vk::DeviceInterface&        vkd    = context.getDeviceInterface();
+       const vk::VkMemoryRequirements  imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
+       de::MovePtr<vk::Allocation>              memory  = context.getDefaultAllocator().allocate(imgReqs, memReqs);
+
+       vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
+
+       return memory;
+}
+
+Move<vk::VkImageView> createAttachmentView (Context& context, vk::VkImage image, vk::VkFormat format)
+{
+       const vk::VkImageViewCreateInfo params =
+       {
+               vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,           // sType
+               DE_NULL,                                                                                        // pNext
+               0u,                                                                                                     // flags
+               image,                                                                                          // image
+               vk::VK_IMAGE_VIEW_TYPE_2D,                                                      // viewType
+               format,                                                                                         // format
+               vk::makeComponentMappingRGBA(),                                         // components
+               { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u,1u },       // subresourceRange
+       };
+
+       return vk::createImageView(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkPipelineLayout> createPipelineLayout (Context& context, vk::VkDescriptorSetLayout descriptorSetLayout)
+{
+       const vk::VkPipelineLayoutCreateInfo params =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,      // sType
+               DE_NULL,                                                                                        // pNext
+               0u,                                                                                                     // flags
+               1u,                                                                                                     // setLayoutCount
+               &descriptorSetLayout,                                                           // pSetLayouts
+               0u,                                                                                                     // pushConstantRangeCount
+               DE_NULL,                                                                                        // pPushConstantRanges
+       };
+
+       return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkCommandPool> createCmdPool (Context& context)
+{
+       const deUint32                                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+       const vk::VkCommandPoolCreateInfo       params                          =
+       {
+               vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,                 // sType
+               DE_NULL,                                                                                                // pNext
+               vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,    // flags
+               queueFamilyIndex,                                                                               // queueFamilyIndex
+       };
+
+       return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkCommandBuffer> createCmdBuffer (Context& context, vk::VkCommandPool cmdPool)
+{
+       const vk::VkCommandBufferAllocateInfo params =
+       {
+               vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,     // sType
+               DE_NULL,                                                                                        // pNext
+               cmdPool,                                                                                        // commandPool
+               vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,                            // level
+               1u,                                                                                                     // bufferCount
+       };
+
+       return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+
+// UniformBlockCaseInstance
+
+class UniformBlockCaseInstance : public vkt::TestInstance
+{
+public:
+                                                                       UniformBlockCaseInstance        (Context&                                               context,
+                                                                                                                                UniformBlockCase::BufferMode   bufferMode,
+                                                                                                                                const UniformLayout&                   layout,
+                                                                                                                                const std::map<int, void*>&    blockPointers);
+       virtual                                                 ~UniformBlockCaseInstance       (void);
+       virtual tcu::TestStatus                 iterate                                         (void);
+
+private:
+       enum
+       {
+               RENDER_WIDTH = 100,
+               RENDER_HEIGHT = 100,
+       };
+
+       vk::Move<VkRenderPass>                  createRenderPass                        (vk::VkFormat format) const;
+       vk::Move<VkFramebuffer>                 createFramebuffer                       (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const;
+       vk::Move<VkDescriptorSetLayout> createDescriptorSetLayout       (void) const;
+       vk::Move<VkDescriptorPool>              createDescriptorPool            (void) const;
+       vk::Move<VkPipeline>                    createPipeline                          (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const;
+
+       vk::VkDescriptorBufferInfo              addUniformData                          (deUint32 size, const void* dataPtr);
+
+       UniformBlockCase::BufferMode    m_bufferMode;
+       const UniformLayout&                    m_layout;
+       const std::map<int, void*>&             m_blockPointers;
+
+       typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >        VkBufferSp;
+       typedef de::SharedPtr<vk::Allocation>                           AllocationSp;
+
+       std::vector<VkBufferSp>                 m_uniformBuffers;
+       std::vector<AllocationSp>               m_uniformAllocs;
+};
+
+UniformBlockCaseInstance::UniformBlockCaseInstance (Context&                                           ctx,
+                                                                                                       UniformBlockCase::BufferMode    bufferMode,
+                                                                                                       const UniformLayout&                    layout,
+                                                                                                       const std::map<int, void*>&             blockPointers)
+       : vkt::TestInstance (ctx)
+       , m_bufferMode          (bufferMode)
+       , m_layout                      (layout)
+       , m_blockPointers       (blockPointers)
+{
+}
+
+UniformBlockCaseInstance::~UniformBlockCaseInstance (void)
+{
+}
+
+tcu::TestStatus UniformBlockCaseInstance::iterate (void)
+{
+       const vk::DeviceInterface&              vk                                      = m_context.getDeviceInterface();
+       const vk::VkDevice                              device                          = m_context.getDevice();
+       const vk::VkQueue                               queue                           = m_context.getUniversalQueue();
+       const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+
+       const float positions[] =
+       {
+               -1.0f, -1.0f, 0.0f, 1.0f,
+               -1.0f, +1.0f, 0.0f, 1.0f,
+               +1.0f, -1.0f, 0.0f, 1.0f,
+               +1.0f, +1.0f, 0.0f, 1.0f
+       };
+
+       const deUint32 indices[] = { 0, 1, 2, 2, 1, 3 };
+
+       vk::Unique<VkBuffer>                            positionsBuffer         (createBuffer(m_context, sizeof(positions), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
+       de::UniquePtr<Allocation>                       positionsAlloc          (allocateAndBindMemory(m_context, *positionsBuffer, MemoryRequirement::HostVisible));
+       vk::Unique<VkBuffer>                            indicesBuffer           (createBuffer(m_context, sizeof(indices), vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT|vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
+       de::UniquePtr<Allocation>                       indicesAlloc            (allocateAndBindMemory(m_context, *indicesBuffer, MemoryRequirement::HostVisible));
+
+       // Upload attrbiutes data
+       {
+               deMemcpy(positionsAlloc->getHostPtr(), positions, sizeof(positions));
+               flushMappedMemoryRange(vk, device, positionsAlloc->getMemory(), positionsAlloc->getOffset(), sizeof(positions));
+
+               deMemcpy(indicesAlloc->getHostPtr(), indices, sizeof(indices));
+               flushMappedMemoryRange(vk, device, indicesAlloc->getMemory(), indicesAlloc->getOffset(), sizeof(indices));
+       }
+
+       vk::Unique<VkImage>                                     colorImage                      (createImage2D(m_context,
+                                                                                                                                                       RENDER_WIDTH,
+                                                                                                                                                       RENDER_HEIGHT,
+                                                                                                                                                       vk::VK_FORMAT_R8G8B8A8_UNORM,
+                                                                                                                                                       vk::VK_IMAGE_TILING_OPTIMAL,
+                                                                                                                                                       vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
+       de::UniquePtr<Allocation>                       colorImageAlloc         (allocateAndBindMemory(m_context, *colorImage, MemoryRequirement::Any));
+       vk::Unique<VkImageView>                         colorImageView          (createAttachmentView(m_context, *colorImage, vk::VK_FORMAT_R8G8B8A8_UNORM));
+
+       vk::Unique<VkDescriptorSetLayout>       descriptorSetLayout     (createDescriptorSetLayout());
+       vk::Unique<VkDescriptorPool>            descriptorPool          (createDescriptorPool());
+
+       const VkDescriptorSetAllocateInfo       descriptorSetAllocateInfo =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,         // VkStructureType                              sType;
+               DE_NULL,                                                                                        // const void*                                  pNext;
+               *descriptorPool,                                                                        // VkDescriptorPool                             descriptorPool;
+               1u,                                                                                                     // deUint32                                             setLayoutCount;
+               &descriptorSetLayout.get()                                                      // const VkDescriptorSetLayout* pSetLayouts;
+       };
+
+       vk::Unique<VkDescriptorSet>                     descriptorSet(vk::allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo));
+
+       // Upload uniform data
+       {
+               vk::DescriptorSetUpdateBuilder  descriptorSetUpdateBuilder;
+               int numBlocks = (int)m_layout.blocks.size();
+
+               if (m_bufferMode == UniformBlockCase::BUFFERMODE_PER_BLOCK)
+               {
+                       for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+                       {
+                               const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
+                               const void*     srcPtr = m_blockPointers.find(blockNdx)->second;
+
+                               vk::VkDescriptorBufferInfo descriptor = addUniformData(block.size, srcPtr);
+                               descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
+                                                                                                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptor);
+                       }
+               }
+               else
+               {
+                       int currentOffset = 0;
+                       std::map<int, int> offsets;
+                       for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+                       {
+                               offsets[blockNdx] = currentOffset;
+                               currentOffset += m_layout.blocks[blockNdx].size;
+                       }
+
+                       deUint32 totalSize = currentOffset;
+                       // The first block index points to the start of the whole data.
+                       const void* srcPtr = m_blockPointers.find(0)->second;
+
+                       vk::VkBuffer buffer = addUniformData(totalSize, srcPtr).buffer;
+
+                       for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+                       {
+                               const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
+                               deUint32 size = block.size;
+
+                               const VkDescriptorBufferInfo    descriptor =
+                               {
+                                       buffer,                                                 // VkBuffer             buffer;
+                                       (deUint32)offsets[blockNdx],    // VkDeviceSize offset;
+                                       size,                                                   // VkDeviceSize range;
+                               };
+
+                               descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
+                                                                                                               vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
+                                                                                                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                                                                                                               &descriptor);
+                       }
+               }
+
+               descriptorSetUpdateBuilder.update(vk, device);
+       }
+
+       vk::Unique<VkRenderPass>                        renderPass                      (createRenderPass(vk::VK_FORMAT_R8G8B8A8_UNORM));
+       vk::Unique<VkFramebuffer>                       framebuffer                     (createFramebuffer(*renderPass, *colorImageView));
+       vk::Unique<VkPipelineLayout>            pipelineLayout          (createPipelineLayout(m_context, *descriptorSetLayout));
+
+       vk::Unique<VkShaderModule>                      vtxShaderModule         (vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
+       vk::Unique<VkShaderModule>                      fragShaderModule        (vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
+       vk::Unique<VkPipeline>                          pipeline                        (createPipeline(*vtxShaderModule, *fragShaderModule, *pipelineLayout, *renderPass));
+       vk::Unique<VkCommandPool>                       cmdPool                         (createCmdPool(m_context));
+       vk::Unique<VkCommandBuffer>                     cmdBuffer                       (createCmdBuffer(m_context, *cmdPool));
+       vk::Unique<VkBuffer>                            readImageBuffer         (createBuffer(m_context, (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4), vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+       de::UniquePtr<Allocation>                       readImageAlloc          (allocateAndBindMemory(m_context, *readImageBuffer, vk::MemoryRequirement::HostVisible));
+
+       // Record command buffer
+       const vk::VkCommandBufferBeginInfo beginInfo    =
+       {
+               vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,        // VkStructureType                                      sType;
+               DE_NULL,                                                                                        // const void*                                          pNext;
+               0u,                                                                                                     // VkCommandBufferUsageFlags            flags;
+               (vk::VkRenderPass)0,                                                            // VkRenderPass                                         renderPass;
+               0u,                                                                                                     // deUint32                                                     subpass;
+               (vk::VkFramebuffer)0,                                                           // VkFramebuffer                                        framebuffer;
+               false,                                                                                          // VkBool32                                                     occlusionQueryEnable;
+               0u,                                                                                                     // VkQueryControlFlags                          queryFlags;
+               0u                                                                                                      // VkQueryPipelineStatisticFlags        pipelineStatistics;
+       };
+       VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &beginInfo));
+
+       const vk::VkClearValue clearValue = vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
+       const vk::VkRenderPassBeginInfo passBeginInfo   =
+       {
+               vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,   // VkStructureType              sType;
+               DE_NULL,                                                                                // const void*                  pNext;
+               *renderPass,                                                                    // VkRenderPass                 renderPass;
+               *framebuffer,                                                                   // VkFramebuffer                framebuffer;
+               { { 0, 0 }, { RENDER_WIDTH, RENDER_HEIGHT } },  // VkRect2D                             renderArea;
+               1u,                                                                                             // deUint32                             clearValueCount;
+               &clearValue,                                                                    // const VkClearValue*  pClearValues;
+       };
+
+       vk.cmdBeginRenderPass(*cmdBuffer, &passBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
+
+       vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+       vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
+
+       const vk::VkDeviceSize offsets[] = { 0u };
+       vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*positionsBuffer, offsets);
+       vk.cmdBindIndexBuffer(*cmdBuffer, *indicesBuffer, (vk::VkDeviceSize)0, vk::VK_INDEX_TYPE_UINT32);
+
+       vk.cmdDrawIndexed(*cmdBuffer, DE_LENGTH_OF_ARRAY(indices), 1u, 0u, 0u, 0u);
+       vk.cmdEndRenderPass(*cmdBuffer);
+
+       // Add render finish barrier
+       {
+               const vk::VkImageMemoryBarrier  renderFinishBarrier =
+               {
+                       vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,             // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext
+                       vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,               // VVkAccessFlags                       srcAccessMask;
+                       vk::VK_ACCESS_TRANSFER_READ_BIT,                                // VkAccessFlags                        dstAccessMask;
+                       vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   // VkImageLayout                        oldLayout;
+                       vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,               // VkImageLayout                        newLayout;
+                       queueFamilyIndex,                                                               // deUint32                                     srcQueueFamilyIndex;
+                       queueFamilyIndex,                                                               // deUint32                                     dstQueueFamilyIndex;
+                       *colorImage,                                                                    // VkImage                                      image;
+                       {
+                               vk::VK_IMAGE_ASPECT_COLOR_BIT,                  // VkImageAspectFlags   aspectMask;
+                               0u,                                                                             // deUint32                             baseMipLevel;
+                               1u,                                                                             // deUint32                             mipLevels;
+                               0u,                                                                             // deUint32                             baseArraySlice;
+                               1u,                                                                             // deUint32                             arraySize;
+                       }                                                                                               // VkImageSubresourceRange      subresourceRange
+               };
+               const void* const barriers[] = { &renderFinishBarrier };
+
+               vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, DE_FALSE, DE_LENGTH_OF_ARRAY(barriers), barriers);
+       }
+
+       // Add Image->Buffer copy command
+       {
+               const vk::VkBufferImageCopy copyParams =
+               {
+                       (vk::VkDeviceSize)0u,                                   // VkDeviceSize                         bufferOffset;
+                       (deUint32)RENDER_WIDTH,                                 // deUint32                                     bufferRowLength;
+                       (deUint32)RENDER_HEIGHT,                                // deUint32                                     bufferImageHeight;
+                       {
+                               vk::VK_IMAGE_ASPECT_COLOR_BIT,  // VkImageAspect        aspect;
+                               0u,                                                             // deUint32                     mipLevel;
+                               0u,                                                             // deUint32                     arrayLayer;
+                               1u,                                                             // deUint32                     arraySize;
+                       },                                                                              // VkImageSubresourceCopy       imageSubresource
+                       { 0u, 0u, 0u },                                                 // VkOffset3D                           imageOffset;
+                       { RENDER_WIDTH, RENDER_HEIGHT, 1u }             // VkExtent3D                           imageExtent;
+               };
+
+               vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
+       }
+
+       // Add copy finish barrier
+       {
+               const vk::VkBufferMemoryBarrier copyFinishBarrier       =
+               {
+                       vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,            // VkStructureType              sType;
+                       DE_NULL,                                                                                        // const void*                  pNext;
+                       VK_ACCESS_TRANSFER_WRITE_BIT,                                           // VkAccessFlags                srcAccessMask;
+                       VK_ACCESS_HOST_READ_BIT,                                                        // VkAccessFlags                dstAccessMask;
+                       queueFamilyIndex,                                                                       // deUint32                             srcQueueFamilyIndex;
+                       queueFamilyIndex,                                                                       // deUint32                             destQueueFamilyIndex;
+                       *readImageBuffer,                                                                       // VkBuffer                             buffer;
+                       0u,                                                                                                     // VkDeviceSize                 offset;
+                       (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4)// VkDeviceSize                     size;
+               };
+               const void* const barriers[] = { &copyFinishBarrier };
+
+               vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+       }
+
+       VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+
+       // Submit the command buffer
+       {
+               const vk::VkFenceCreateInfo fenceParams =
+               {
+                       vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,        // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkFenceCreateFlags   flags;
+               };
+               const Unique<vk::VkFence> fence(vk::createFence(vk, device, &fenceParams));
+
+               const VkSubmitInfo                      submitInfo      =
+               {
+                       VK_STRUCTURE_TYPE_SUBMIT_INFO,  // VkStructureType                      sType;
+                       DE_NULL,                                                // const void*                          pNext;
+                       0u,                                                             // deUint32                                     waitSemaphoreCount;
+                       DE_NULL,                                                // const VkSemaphore*           pWaitSemaphores;
+                       1u,                                                             // deUint32                                     commandBufferCount;
+                       &cmdBuffer.get(),                               // const VkCommandBuffer*       pCommandBuffers;
+                       0u,                                                             // deUint32                                     signalSemaphoreCount;
+                       DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+               };
+
+               VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
+               VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
+       }
+
+       // Read back the results
+       tcu::Surface surface(RENDER_WIDTH, RENDER_HEIGHT);
+       {
+               const tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+               const tcu::ConstPixelBufferAccess imgAccess(textureFormat, RENDER_WIDTH, RENDER_HEIGHT, 1, readImageAlloc->getHostPtr());
+               const vk::VkDeviceSize bufferSize = RENDER_WIDTH * RENDER_HEIGHT * 4;
+               invalidateMappedMemoryRange(vk, device, readImageAlloc->getMemory(), readImageAlloc->getOffset(), bufferSize);
+
+               tcu::copy(surface.getAccess(), imgAccess);
+       }
+
+       // Check if the result image is all white
+       tcu::RGBA white(tcu::RGBA::white());
+       int numFailedPixels = 0;
+
+       for (int y = 0; y < surface.getHeight(); y++)
+       {
+               for (int x = 0; x < surface.getWidth(); x++)
+               {
+                       if (surface.getPixel(x, y) != white)
+                               numFailedPixels += 1;
+               }
+       }
+
+       if (numFailedPixels > 0)
+       {
+               tcu::TestLog& log = m_context.getTestContext().getLog();
+               log << tcu::TestLog::Image("Image", "Rendered image", surface);
+               log << tcu::TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels" << tcu::TestLog::EndMessage;
+
+               for (size_t blockNdx = 0; blockNdx < m_layout.blocks.size(); blockNdx++)
+               {
+                       const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
+                       log << tcu::TestLog::Message << "Block index: " << blockNdx << " infos: " << block << tcu::TestLog::EndMessage;
+               }
+
+               for (size_t uniformNdx = 0; uniformNdx < m_layout.uniforms.size(); uniformNdx++)
+               {
+                       log << tcu::TestLog::Message << "Uniform index: " << uniformNdx << " infos: " << m_layout.uniforms[uniformNdx] << tcu::TestLog::EndMessage;
+               }
+
+               return tcu::TestStatus::fail("Detected non-white pixels");
+       }
+       else
+               return tcu::TestStatus::pass("Full white image ok");
+}
+
+vk::VkDescriptorBufferInfo UniformBlockCaseInstance::addUniformData (deUint32 size, const void* dataPtr)
+{
+       const VkDevice                                  vkDevice                        = m_context.getDevice();
+       const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
+
+       Move<VkBuffer>                                  buffer  = createBuffer(m_context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
+       de::MovePtr<Allocation>                 alloc   = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
+
+       deMemcpy(alloc->getHostPtr(), dataPtr, size);
+       flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), size);
+
+       const VkDescriptorBufferInfo                    descriptor                      =
+       {
+               *buffer,                                // VkBuffer             buffer;
+               0u,                                             // VkDeviceSize offset;
+               size,                                   // VkDeviceSize range;
+
+       };
+
+       m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
+       m_uniformAllocs.push_back(AllocationSp(alloc.release()));
+
+       return descriptor;
+}
+
+vk::Move<VkRenderPass> UniformBlockCaseInstance::createRenderPass (vk::VkFormat format) const
+{
+       const VkDevice                                  vkDevice                                = m_context.getDevice();
+       const DeviceInterface&                  vk                                              = m_context.getDeviceInterface();
+
+       const VkAttachmentDescription   attachmentDescription   =
+       {
+               0u,                                                                                             // VkAttachmentDescriptorFlags  flags;
+               format,                                                                                 // VkFormat                                             format;
+               VK_SAMPLE_COUNT_1_BIT,                                                  // VkSampleCountFlagBits                samples;
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                                    // VkAttachmentLoadOp                   loadOp;
+               VK_ATTACHMENT_STORE_OP_STORE,                                   // VkAttachmentStoreOp                  storeOp;
+               VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                // VkAttachmentLoadOp                   stencilLoadOp;
+               VK_ATTACHMENT_STORE_OP_DONT_CARE,                               // VkAttachmentStoreOp                  stencilStoreOp;
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               // VkImageLayout                                initialLayout;
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               // VkImageLayout                                finalLayout;
+       };
+
+       const VkAttachmentReference             attachmentReference             =
+       {
+               0u,                                                                                     // deUint32                     attachment;
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL        // VkImageLayout        layout;
+       };
+
+
+       const VkSubpassDescription              subpassDescription              =
+       {
+               0u,                                                                                             // VkSubpassDescriptionFlags    flags;
+               VK_PIPELINE_BIND_POINT_GRAPHICS,                                // VkPipelineBindPoint                  pipelineBindPoint;
+               0u,                                                                                             // deUint32                                             inputAttachmentCount;
+               DE_NULL,                                                                                // const VkAttachmentReference* pInputAttachments;
+               1u,                                                                                             // deUint32                                             colorAttachmentCount;
+               &attachmentReference,                                                   // const VkAttachmentReference* pColorAttachments;
+               DE_NULL,                                                                                // const VkAttachmentReference* pResolveAttachments;
+               DE_NULL,                                                                                // const VkAttachmentReference* pDepthStencilAttachment;
+               0u,                                                                                             // deUint32                                             preserveAttachmentCount;
+               DE_NULL                                                                                 // const VkAttachmentReference* pPreserveAttachments;
+       };
+
+       const VkRenderPassCreateInfo    renderPassParams                =
+       {
+               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,              // VkStructureType                                      sType;
+               DE_NULL,                                                                                // const void*                                          pNext;
+               0u,                                                                                             // VkRenderPassCreateFlags                      flags;
+               1u,                                                                                             // deUint32                                                     attachmentCount;
+               &attachmentDescription,                                                 // const VkAttachmentDescription*       pAttachments;
+               1u,                                                                                             // deUint32                                                     subpassCount;
+               &subpassDescription,                                                    // const VkSubpassDescription*          pSubpasses;
+               0u,                                                                                             // deUint32                                                     dependencyCount;
+               DE_NULL                                                                                 // const VkSubpassDependency*           pDependencies;
+       };
+
+       return vk::createRenderPass(vk, vkDevice, &renderPassParams);
+}
+
+vk::Move<VkFramebuffer> UniformBlockCaseInstance::createFramebuffer (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const
+{
+       const VkDevice                                  vkDevice                        = m_context.getDevice();
+       const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
+
+       const VkFramebufferCreateInfo   framebufferParams       =
+       {
+               VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,              // VkStructureType                      sType;
+               DE_NULL,                                                                                // const void*                          pNext;
+               0u,                                                                                             // VkFramebufferCreateFlags     flags;
+               renderPass,                                                                             // VkRenderPass                         renderPass;
+               1u,                                                                                             // deUint32                                     attachmentCount;
+               &colorImageView,                                                                // const VkImageView*           pAttachments;
+               RENDER_WIDTH,                                                                   // deUint32                                     width;
+               RENDER_HEIGHT,                                                                  // deUint32                                     height;
+               1u                                                                                              // deUint32                                     layers;
+       };
+
+       return vk::createFramebuffer(vk, vkDevice, &framebufferParams);
+}
+
+vk::Move<VkDescriptorSetLayout> UniformBlockCaseInstance::createDescriptorSetLayout (void) const
+{
+       int numBlocks = (int)m_layout.blocks.size();
+       int lastBindingNdx = -1;
+       std::vector<int> lengths;
+
+       for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+       {
+               const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
+
+               if (block.bindingNdx == lastBindingNdx)
+               {
+                       lengths.back()++;
+               }
+               else
+               {
+                       lengths.push_back(1);
+                       lastBindingNdx = block.bindingNdx;
+               }
+       }
+
+       vk::DescriptorSetLayoutBuilder layoutBuilder;
+       for (size_t i = 0; i < lengths.size(); i++)
+       {
+               if (lengths[i] > 0)
+               {
+                       layoutBuilder.addArrayBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, lengths[i], vk::VK_SHADER_STAGE_ALL);
+               }
+               else
+               {
+                       layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
+               }
+       }
+
+       return layoutBuilder.build(m_context.getDeviceInterface(), m_context.getDevice());
+}
+
+vk::Move<VkDescriptorPool> UniformBlockCaseInstance::createDescriptorPool (void) const
+{
+       vk::DescriptorPoolBuilder poolBuilder;
+
+       return poolBuilder
+               .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)m_layout.blocks.size())
+               .build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+}
+
+vk::Move<VkPipeline> UniformBlockCaseInstance::createPipeline (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const
+{
+       const VkDevice                                                                  vkDevice                                = m_context.getDevice();
+       const DeviceInterface&                                                  vk                                              = m_context.getDeviceInterface();
+
+       const VkVertexInputBindingDescription                   vertexBinding                   =
+       {
+               0,                                                                      // deUint32                                     binding;
+               sizeof(float) * 4,                                      // deUint32                                     strideInBytes;
+               VK_VERTEX_INPUT_RATE_VERTEX                     // VkVertexInputStepRate        inputRate;
+       };
+
+       const VkVertexInputAttributeDescription                 vertexAttribute                 =
+       {
+               0,                                                                      // deUint32             location;
+               0,                                                                      // deUint32             binding;
+               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat             format;
+               0u                                                                      // deUint32             offset;
+       };
+
+       const VkPipelineShaderStageCreateInfo                   shaderStages[2] =
+       {
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                                // const void*                                          pNext;
+                       0u,                                                                                                             // VkPipelineShaderStageCreateFlags     flags;
+                       VK_SHADER_STAGE_VERTEX_BIT,                                                             // VkShaderStageFlagBits                        stage;
+                       vtxShaderModule,                                                                                // VkShaderModule                                       module;
+                       "main",                                                                                                 // const char*                                          pName;
+                       DE_NULL                                                                                                 // const VkSpecializationInfo*          pSpecializationInfo;
+               },
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                                // const void*                                          pNext;
+                       0u,                                                                                                             // VkPipelineShaderStageCreateFlags flags;
+                       VK_SHADER_STAGE_FRAGMENT_BIT,                                                   // VkShaderStageFlagBits                        stage;
+                       fragShaderModule,                                                                               // VkShaderModule                                       module;
+                       "main",                                                                                                 // const char*                                          pName;
+                       DE_NULL                                                                                                 // const VkSpecializationInfo*          pSpecializationInfo;
+               }
+       };
+
+       const VkPipelineVertexInputStateCreateInfo              vertexInputStateParams          =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,      // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineVertexInputStateCreateFlags        flags;
+               1u,                                                                                                                     // deUint32                                                                     vertexBindingDescriptionCount;
+               &vertexBinding,                                                                                         // const VkVertexInputBindingDescription*       pVertexBindingDescriptions;
+               1u,                                                                                                                     // deUint32                                                                     vertexAttributeDescriptionCount;
+               &vertexAttribute,                                                                                       // const VkVertexInputAttributeDescription*     pVertexAttributeDescriptions;
+       };
+
+       const VkPipelineInputAssemblyStateCreateInfo    inputAssemblyStateParams        =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,// VkStructureType                                                  sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineInputAssemblyStateCreateFlags      flags;
+               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,                                            // VkPrimitiveTopology                                          topology;
+               false                                                                                                           // VkBool32                                                                     primitiveRestartEnable;
+       };
+
+       const VkViewport                                                                viewport                                        =
+       {
+               0.0f,                                   // float        originX;
+               0.0f,                                   // float        originY;
+               (float)RENDER_WIDTH,    // float        width;
+               (float)RENDER_HEIGHT,   // float        height;
+               0.0f,                                   // float        minDepth;
+               1.0f                                    // float        maxDepth;
+       };
+
+
+       const VkRect2D                                                                  scissor                                         =
+       {
+               {
+                       0u,                             // deUint32     x;
+                       0u,                             // deUint32     y;
+               },                                              // VkOffset2D   offset;
+               {
+                       RENDER_WIDTH,   // deUint32     width;
+                       RENDER_HEIGHT,  // deUint32     height;
+               },                                              // VkExtent2D   extent;
+       };
+
+       const VkPipelineViewportStateCreateInfo                 viewportStateParams                     =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,          // VkStructureType                                              sType;
+               DE_NULL,                                                                                                        // const void*                                                  pNext;
+               0u,                                                                                                                     // VkPipelineViewportStateCreateFlags   flags;
+               1u,                                                                                                                     // deUint32                                                             viewportCount;
+               &viewport,                                                                                                      // const VkViewport*                                    pViewports;
+               1u,                                                                                                                     // deUint32                                                             scissorsCount;
+               &scissor,                                                                                                       // const VkRect2D*                                              pScissors;
+       };
+
+       const VkPipelineRasterizationStateCreateInfo                    rasterStateParams                       =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType                                                  sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineRasterizationStateCreateFlags      flags;
+               false,                                                                                                          // VkBool32                                                                     depthClampEnable;
+               false,                                                                                                          // VkBool32                                                                     rasterizerDiscardEnable;
+               VK_POLYGON_MODE_FILL,                                                                           // VkPolygonMode                                                        polygonMode;
+               VK_CULL_MODE_NONE,                                                                                      // VkCullModeFlags                                                      cullMode;
+               VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                        // VkFrontFace                                                          frontFace;
+               false,                                                                                                          // VkBool32                                                                     depthBiasEnable;
+               0.0f,                                                                                                           // float                                                                        depthBiasConstantFactor;
+               0.0f,                                                                                                           // float                                                                        depthBiasClamp;
+               0.0f,                                                                                                           // float                                                                        depthBiasSlopeFactor;
+               1.0f,                                                                                                           // float                                                                        lineWidth;
+       };
+
+       const VkPipelineColorBlendAttachmentState               colorBlendAttachmentState       =
+       {
+               false,                                                                                                                                          // VkBool32                     blendEnable;
+               VK_BLEND_FACTOR_ONE,                                                                                                            // VkBlend                      srcBlendColor;
+               VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlend                      destBlendColor;
+               VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp            blendOpColor;
+               VK_BLEND_FACTOR_ONE,                                                                                                            // VkBlend                      srcBlendAlpha;
+               VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlend                      destBlendAlpha;
+               VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp            blendOpAlpha;
+               VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                                           // VkChannelFlags       channelWriteMask;
+               VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+       };
+
+       const VkPipelineColorBlendStateCreateInfo               colorBlendStateParams           =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       // VkStructureType                                                              sType;
+               DE_NULL,                                                                                                        // const void*                                                                  pNext;
+               0u,                                                                                                                     // VkPipelineColorBlendStateCreateFlags                 flags;
+               false,                                                                                                          // VkBool32                                                                             logicOpEnable;
+               VK_LOGIC_OP_COPY,                                                                                       // VkLogicOp                                                                    logicOp;
+               1u,                                                                                                                     // deUint32                                                                             attachmentCount;
+               &colorBlendAttachmentState,                                                                     // const VkPipelineColorBlendAttachmentState*   pAttachments;
+               { 0.0f, 0.0f, 0.0f, 0.0f },                                                                     // float                                                                                blendConstants[4];
+       };
+
+       const VkPipelineDynamicStateCreateInfo                  dynamicStateInfo                        =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,   // VkStructureType                                              sType;
+               DE_NULL,                                                                                                // const void*                                                  pNext;
+               0u,                                                                                                             // VkPipelineDynamicStateCreateFlags    flags;
+               0u,                                                                                                             // deUint32                                                             dynamicStateCount;
+               DE_NULL                                                                                                 // const VkDynamicState*                                pDynamicStates;
+       };
+
+       const VkGraphicsPipelineCreateInfo                              graphicsPipelineParams          =
+       {
+               VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+               DE_NULL,                                                                                        // const void*                                                                          pNext;
+               0u,                                                                                                     // VkPipelineCreateFlags                                                        flags;
+               2u,                                                                                                     // deUint32                                                                                     stageCount;
+               shaderStages,                                                                           // const VkPipelineShaderStageCreateInfo*                       pStages;
+               &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+               &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+               DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+               &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+               &rasterStateParams,                                                                     // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
+               DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+               DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+               &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+               &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+               pipelineLayout,                                                                         // VkPipelineLayout                                                                     layout;
+               renderPass,                                                                                     // VkRenderPass                                                                         renderPass;
+               0u,                                                                                                     // deUint32                                                                                     subpass;
+               0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+               0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+       };
+
+       return vk::createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+}
+
+} // anonymous (utilities)
+
+// UniformBlockCase.
+
+UniformBlockCase::UniformBlockCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode)
+       : TestCase              (testCtx, name, description)
+       , m_bufferMode  (bufferMode)
+{
+}
+
+UniformBlockCase::~UniformBlockCase (void)
+{
+}
+
+void UniformBlockCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       DE_ASSERT(!m_vertShaderSource.empty());
+       DE_ASSERT(!m_fragShaderSource.empty());
+
+       programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
+       programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
+}
+
+TestInstance* UniformBlockCase::createInstance (Context& context) const
+{
+       return new UniformBlockCaseInstance(context, m_bufferMode, m_uniformLayout, m_blockPointers);
+}
+
+void UniformBlockCase::init (void)
+{
+       // Compute reference layout.
+       computeStd140Layout(m_uniformLayout, m_interface);
+
+       // Assign storage for reference values.
+       {
+               int totalSize = 0;
+               for (std::vector<BlockLayoutEntry>::const_iterator blockIter = m_uniformLayout.blocks.begin(); blockIter != m_uniformLayout.blocks.end(); blockIter++)
+                       totalSize += blockIter->size;
+               m_data.resize(totalSize);
+
+               // Pointers for each block.
+               int curOffset = 0;
+               for (int blockNdx = 0; blockNdx < (int)m_uniformLayout.blocks.size(); blockNdx++)
+               {
+                       m_blockPointers[blockNdx] = &m_data[0] + curOffset;
+                       curOffset += m_uniformLayout.blocks[blockNdx].size;
+               }
+       }
+
+       // Generate values.
+       generateValues(m_uniformLayout, m_blockPointers, 1 /* seed */);
+
+       // Generate shaders.
+       m_vertShaderSource = generateVertexShader(m_interface, m_uniformLayout, m_blockPointers);
+       m_fragShaderSource = generateFragmentShader(m_interface, m_uniformLayout, m_blockPointers);
+}
+
+} // ubo
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp
new file mode 100644 (file)
index 0000000..cb883c1
--- /dev/null
@@ -0,0 +1,332 @@
+#ifndef _VKTUNIFORMBLOCKCASE_HPP
+#define _VKTUNIFORMBLOCKCASE_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 Uniform block tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "deSharedPtr.hpp"
+#include "vktTestCase.hpp"
+#include "tcuDefs.hpp"
+#include "gluShaderUtil.hpp"
+
+#include <map>
+
+namespace vkt
+{
+namespace ubo
+{
+
+// Uniform block details.
+
+enum UniformFlags
+{
+       PRECISION_LOW           = (1<<0),
+       PRECISION_MEDIUM        = (1<<1),
+       PRECISION_HIGH          = (1<<2),
+       PRECISION_MASK          = PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH,
+
+       LAYOUT_SHARED           = (1<<3),
+       LAYOUT_PACKED           = (1<<4),
+       LAYOUT_STD140           = (1<<5),
+       LAYOUT_ROW_MAJOR        = (1<<6),
+       LAYOUT_COLUMN_MAJOR     = (1<<7),       //!< \note Lack of both flags means column-major matrix.
+       LAYOUT_MASK                     = LAYOUT_SHARED|LAYOUT_PACKED|LAYOUT_STD140|LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR,
+
+       DECLARE_VERTEX          = (1<<8),
+       DECLARE_FRAGMENT        = (1<<9),
+       DECLARE_BOTH            = DECLARE_VERTEX|DECLARE_FRAGMENT,
+
+       UNUSED_VERTEX           = (1<<10),      //!< Uniform or struct member is not read in vertex shader.
+       UNUSED_FRAGMENT         = (1<<11),      //!< Uniform or struct member is not read in fragment shader.
+       UNUSED_BOTH                     = UNUSED_VERTEX|UNUSED_FRAGMENT
+};
+
+class StructType;
+
+class VarType
+{
+public:
+                                               VarType                 (void);
+                                               VarType                 (const VarType& other);
+                                               VarType                 (glu::DataType basicType, deUint32 flags);
+                                               VarType                 (const VarType& elementType, int arraySize);
+       explicit                        VarType                 (const StructType* structPtr);
+                                               ~VarType                (void);
+
+       bool                            isBasicType             (void) const    { return m_type == TYPE_BASIC;  }
+       bool                            isArrayType             (void) const    { return m_type == TYPE_ARRAY;  }
+       bool                            isStructType    (void) const    { return m_type == TYPE_STRUCT; }
+
+       deUint32                        getFlags                (void) const    { return m_flags;                                       }
+       glu::DataType           getBasicType    (void) const    { return m_data.basicType;                      }
+
+       const VarType&          getElementType  (void) const    { return *m_data.array.elementType;     }
+       int                                     getArraySize    (void) const    { return m_data.array.size;                     }
+
+       const StructType&       getStruct               (void) const    { return *m_data.structPtr;                     }
+
+       VarType&                        operator=               (const VarType& other);
+
+private:
+       enum Type
+       {
+               TYPE_BASIC,
+               TYPE_ARRAY,
+               TYPE_STRUCT,
+
+               TYPE_LAST
+       };
+
+       Type                            m_type;
+       deUint32                        m_flags;
+       union Data
+       {
+               glu::DataType           basicType;
+               struct
+               {
+                       VarType*                elementType;
+                       int                             size;
+               } array;
+               const StructType*       structPtr;
+
+               Data (void)
+               {
+                       array.elementType       = DE_NULL;
+                       array.size                      = 0;
+               };
+       } m_data;
+};
+
+class StructMember
+{
+public:
+                                               StructMember    (const std::string& name, const VarType& type, deUint32 flags)
+                                                       : m_name(name), m_type(type), m_flags(flags)
+                                               {}
+                                               StructMember    (void)
+                                                       : m_flags(0)
+                                               {}
+
+       const std::string&      getName                 (void) const { return m_name;   }
+       const VarType&          getType                 (void) const { return m_type;   }
+       deUint32                        getFlags                (void) const { return m_flags;  }
+
+private:
+       std::string                     m_name;
+       VarType                         m_type;
+       deUint32                        m_flags;
+};
+
+class StructType
+{
+public:
+       typedef std::vector<StructMember>::iterator                     Iterator;
+       typedef std::vector<StructMember>::const_iterator       ConstIterator;
+
+                                                               StructType              (const std::string& typeName) : m_typeName(typeName) {}
+                                                               ~StructType             (void) {}
+
+       const std::string&                      getTypeName             (void) const    { return m_typeName;                    }
+       bool                                            hasTypeName             (void) const    { return !m_typeName.empty();   }
+
+       inline Iterator                         begin                   (void)                  { return m_members.begin();             }
+       inline ConstIterator            begin                   (void) const    { return m_members.begin();             }
+       inline Iterator                         end                             (void)                  { return m_members.end();               }
+       inline ConstIterator            end                             (void) const    { return m_members.end();               }
+
+       void                                            addMember               (const std::string& name, const VarType& type, deUint32 flags = 0);
+
+private:
+       std::string                                     m_typeName;
+       std::vector<StructMember>       m_members;
+};
+
+class Uniform
+{
+public:
+                                               Uniform                 (const std::string& name, const VarType& type, deUint32 flags = 0);
+
+       const std::string&      getName                 (void) const { return m_name;   }
+       const VarType&          getType                 (void) const { return m_type;   }
+       deUint32                        getFlags                (void) const { return m_flags;  }
+
+private:
+       std::string                     m_name;
+       VarType                         m_type;
+       deUint32                        m_flags;
+};
+
+class UniformBlock
+{
+public:
+       typedef std::vector<Uniform>::iterator                  Iterator;
+       typedef std::vector<Uniform>::const_iterator    ConstIterator;
+
+                                                       UniformBlock            (const std::string& blockName);
+
+       const std::string&              getBlockName            (void) const { return m_blockName;              }
+       const std::string&              getInstanceName         (void) const { return m_instanceName;   }
+       bool                                    hasInstanceName         (void) const { return !m_instanceName.empty();  }
+       bool                                    isArray                         (void) const { return m_arraySize > 0;                  }
+       int                                             getArraySize            (void) const { return m_arraySize;                              }
+       deUint32                                getFlags                        (void) const { return m_flags;                                  }
+
+       void                                    setInstanceName         (const std::string& name)       { m_instanceName = name;                        }
+       void                                    setFlags                        (deUint32 flags)                        { m_flags = flags;                                      }
+       void                                    setArraySize            (int arraySize)                         { m_arraySize = arraySize;                      }
+       void                                    addUniform                      (const Uniform& uniform)        { m_uniforms.push_back(uniform);        }
+
+       inline Iterator                 begin                           (void)                  { return m_uniforms.begin();    }
+       inline ConstIterator    begin                           (void) const    { return m_uniforms.begin();    }
+       inline Iterator                 end                                     (void)                  { return m_uniforms.end();              }
+       inline ConstIterator    end                                     (void) const    { return m_uniforms.end();              }
+
+private:
+       std::string                             m_blockName;
+       std::string                             m_instanceName;
+       std::vector<Uniform>    m_uniforms;
+       int                                             m_arraySize;    //!< Array size or 0 if not interface block array.
+       deUint32                                m_flags;
+};
+
+typedef de::SharedPtr<StructType>      StructTypeSP;
+typedef de::SharedPtr<UniformBlock>    UniformBlockSP;
+
+class ShaderInterface
+{
+public:
+                                                               ShaderInterface                 (void);
+                                                               ~ShaderInterface                (void);
+
+       StructType&                                     allocStruct                             (const std::string& name);
+       void                                            getNamedStructs                 (std::vector<const StructType*>& structs) const;
+
+       UniformBlock&                           allocBlock                              (const std::string& name);
+
+       int                                                     getNumUniformBlocks             (void) const    { return (int)m_uniformBlocks.size();   }
+       const UniformBlock&                     getUniformBlock                 (int ndx) const { return *m_uniformBlocks[ndx];                 }
+
+private:
+       std::vector<StructTypeSP>               m_structs;
+       std::vector<UniformBlockSP>             m_uniformBlocks;
+};
+
+struct BlockLayoutEntry
+{
+       BlockLayoutEntry (void)
+               : size(0)
+       {
+       }
+
+       std::string                     name;
+       int                                     size;
+       std::vector<int>        activeUniformIndices;
+       int                                     bindingNdx;
+       int                                     instanceNdx;
+};
+
+struct UniformLayoutEntry
+{
+       UniformLayoutEntry (void)
+               : type                  (glu::TYPE_LAST)
+               , size                  (0)
+               , blockNdx              (-1)
+               , offset                (-1)
+               , arrayStride   (-1)
+               , matrixStride  (-1)
+               , isRowMajor    (false)
+               , instanceNdx   (0)
+       {
+       }
+
+       std::string                     name;
+       glu::DataType           type;
+       int                                     size;
+       int                                     blockNdx;
+       int                                     offset;
+       int                                     arrayStride;
+       int                                     matrixStride;
+       bool                            isRowMajor;
+       int                                     instanceNdx;
+};
+
+class UniformLayout
+{
+public:
+       std::vector<BlockLayoutEntry>           blocks;
+       std::vector<UniformLayoutEntry>         uniforms;
+
+       int                                                                     getUniformIndex                 (const std::string& name) const;
+       int                                                                     getBlockIndex                   (const std::string& name) const;
+};
+
+class UniformBlockCase : public vkt::TestCase
+{
+public:
+       enum BufferMode
+       {
+               BUFFERMODE_SINGLE = 0,  //!< Single buffer shared between uniform blocks.
+               BUFFERMODE_PER_BLOCK,   //!< Per-block buffers
+
+               BUFFERMODE_LAST
+       };
+
+                                                               UniformBlockCase                        (tcu::TestContext&      testCtx,
+                                                                                                                        const std::string&     name,
+                                                                                                                        const std::string&     description,
+                                                                                                                        BufferMode                     bufferMode);
+                                                               ~UniformBlockCase                       (void);
+
+       virtual void                            initPrograms                            (vk::SourceCollections& programCollection) const;
+       virtual TestInstance*           createInstance                          (Context& context) const;
+
+protected:
+       void                                            init                                            (void);
+
+       BufferMode                                      m_bufferMode;
+       ShaderInterface                         m_interface;
+
+private:
+       std::string                                     m_vertShaderSource;
+       std::string                                     m_fragShaderSource;
+
+       std::vector<deUint8>            m_data;                         //!< Data.
+       std::map<int, void*>            m_blockPointers;        //!< Reference block pointers.
+       UniformLayout                           m_uniformLayout;        //!< std140 layout.
+};
+
+} // ubo
+} // vkt
+
+#endif // _VKTUNIFORMBLOCKCASE_HPP
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp
new file mode 100644 (file)
index 0000000..4f0f815
--- /dev/null
@@ -0,0 +1,840 @@
+/*------------------------------------------------------------------------
+ * 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 Uniform block tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktUniformBlockTests.hpp"
+
+#include "vktUniformBlockCase.hpp"
+#include "vktRandomUniformBlockCase.hpp"
+
+#include "tcuCommandLine.hpp"
+#include "deStringUtil.hpp"
+
+namespace vkt
+{
+namespace ubo
+{
+
+namespace
+{
+
+class BlockBasicTypeCase : public UniformBlockCase
+{
+public:
+       BlockBasicTypeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const VarType& type, deUint32 layoutFlags, int numInstances)
+               : UniformBlockCase(testCtx, name, description, BUFFERMODE_PER_BLOCK)
+       {
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("var", type, 0));
+               block.setFlags(layoutFlags);
+
+               if (numInstances > 0)
+               {
+                       block.setArraySize(numInstances);
+                       block.setInstanceName("block");
+               }
+
+               init();
+       }
+};
+
+static void createBlockBasicTypeCases (tcu::TestCaseGroup* group, tcu::TestContext& testCtx, const std::string& name, const VarType& type, deUint32 layoutFlags, int numInstances = 0)
+{
+       group->addChild(new BlockBasicTypeCase(testCtx, name + "_vertex",       "", type, layoutFlags|DECLARE_VERTEX,                                   numInstances));
+       group->addChild(new BlockBasicTypeCase(testCtx, name + "_fragment",     "", type, layoutFlags|DECLARE_FRAGMENT,                                 numInstances));
+
+       if (!(layoutFlags & LAYOUT_PACKED))
+               group->addChild(new BlockBasicTypeCase(testCtx, name + "_both", "", type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  numInstances));
+}
+
+class BlockSingleStructCase : public UniformBlockCase
+{
+public:
+       BlockSingleStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
+               typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
+
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("s", VarType(&typeS), 0));
+               block.setFlags(layoutFlags);
+
+               if (numInstances > 0)
+               {
+                       block.setInstanceName("block");
+                       block.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class BlockSingleStructArrayCase : public UniformBlockCase
+{
+public:
+       BlockSingleStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
+               typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
+
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
+               block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
+               block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
+               block.setFlags(layoutFlags);
+
+               if (numInstances > 0)
+               {
+                       block.setInstanceName("block");
+                       block.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class BlockSingleNestedStructCase : public UniformBlockCase
+{
+public:
+       BlockSingleNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
+               typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
+
+               StructType& typeT = m_interface.allocStruct("T");
+               typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
+               typeT.addMember("b", VarType(&typeS));
+
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("s", VarType(&typeS), 0));
+               block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
+               block.addUniform(Uniform("t", VarType(&typeT), 0));
+               block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
+               block.setFlags(layoutFlags);
+
+               if (numInstances > 0)
+               {
+                       block.setInstanceName("block");
+                       block.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class BlockSingleNestedStructArrayCase : public UniformBlockCase
+{
+public:
+       BlockSingleNestedStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
+               typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
+
+               StructType& typeT = m_interface.allocStruct("T");
+               typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
+               typeT.addMember("b", VarType(VarType(&typeS), 3));
+
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("s", VarType(&typeS), 0));
+               block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
+               block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
+               block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
+               block.setFlags(layoutFlags);
+
+               if (numInstances > 0)
+               {
+                       block.setInstanceName("block");
+                       block.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class BlockMultiBasicTypesCase : public UniformBlockCase
+{
+public:
+       BlockMultiBasicTypesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               UniformBlock& blockA = m_interface.allocBlock("BlockA");
+               blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
+               blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
+               blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
+               blockA.setInstanceName("blockA");
+               blockA.setFlags(flagsA);
+
+               UniformBlock& blockB = m_interface.allocBlock("BlockB");
+               blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
+               blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
+               blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
+               blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
+               blockB.setInstanceName("blockB");
+               blockB.setFlags(flagsB);
+
+               if (numInstances > 0)
+               {
+                       blockA.setArraySize(numInstances);
+                       blockB.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class BlockMultiNestedStructCase : public UniformBlockCase
+{
+public:
+       BlockMultiNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
+               typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
+
+               StructType& typeT = m_interface.allocStruct("T");
+               typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
+               typeT.addMember("b", VarType(&typeS));
+               typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
+
+               UniformBlock& blockA = m_interface.allocBlock("BlockA");
+               blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
+               blockA.addUniform(Uniform("b", VarType(&typeS)));
+               blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
+               blockA.setInstanceName("blockA");
+               blockA.setFlags(flagsA);
+
+               UniformBlock& blockB = m_interface.allocBlock("BlockB");
+               blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
+               blockB.addUniform(Uniform("b", VarType(&typeT)));
+               blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
+               blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
+               blockB.setInstanceName("blockB");
+               blockB.setFlags(flagsB);
+
+               if (numInstances > 0)
+               {
+                       blockA.setArraySize(numInstances);
+                       blockB.setArraySize(numInstances);
+               }
+
+               init();
+       }
+};
+
+class Block2LevelStructArrayCase : public UniformBlockCase
+{
+public:
+       Block2LevelStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
+               : UniformBlockCase      (testCtx, name, description, bufferMode)
+               , m_layoutFlags         (layoutFlags)
+               , m_numInstances        (numInstances)
+       {
+               StructType& typeS = m_interface.allocStruct("S");
+               typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
+               typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM), 4));
+               typeS.addMember("c", VarType(glu::TYPE_UINT, PRECISION_LOW));
+
+               UniformBlock& block = m_interface.allocBlock("Block");
+               block.addUniform(Uniform("u", VarType(glu::TYPE_INT, PRECISION_MEDIUM)));
+               block.addUniform(Uniform("s", VarType(VarType(VarType(&typeS), 3), 2)));
+               block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_MEDIUM)));
+               block.setFlags(m_layoutFlags);
+
+               if (m_numInstances > 0)
+               {
+                       block.setInstanceName("block");
+                       block.setArraySize(m_numInstances);
+               }
+
+               init();
+       }
+
+private:
+       deUint32        m_layoutFlags;
+       int                     m_numInstances;
+};
+
+void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
+{
+       tcu::TestCaseGroup* group = new tcu::TestCaseGroup(testCtx, groupName, description);
+       parentGroup->addChild(group);
+
+       baseSeed += (deUint32)testCtx.getCommandLine().getBaseSeed();
+
+       for (int ndx = 0; ndx < numCases; ndx++)
+               group->addChild(new RandomUniformBlockCase(testCtx, de::toString(ndx), "", bufferMode, features, (deUint32)ndx + baseSeed));
+}
+
+// UniformBlockTests
+
+class UniformBlockTests : public tcu::TestCaseGroup
+{
+public:
+                                                       UniformBlockTests               (tcu::TestContext& testCtx);
+                                                       ~UniformBlockTests              (void);
+
+       void                                    init                                    (void);
+
+private:
+                                                       UniformBlockTests               (const UniformBlockTests& other);
+       UniformBlockTests&              operator=                               (const UniformBlockTests& other);
+};
+
+UniformBlockTests::UniformBlockTests (tcu::TestContext& testCtx)
+       : TestCaseGroup(testCtx, "ubo", "Uniform Block tests")
+{
+}
+
+UniformBlockTests::~UniformBlockTests (void)
+{
+}
+
+void UniformBlockTests::init (void)
+{
+       static const glu::DataType basicTypes[] =
+       {
+               glu::TYPE_FLOAT,
+               glu::TYPE_FLOAT_VEC2,
+               glu::TYPE_FLOAT_VEC3,
+               glu::TYPE_FLOAT_VEC4,
+               glu::TYPE_INT,
+               glu::TYPE_INT_VEC2,
+               glu::TYPE_INT_VEC3,
+               glu::TYPE_INT_VEC4,
+               glu::TYPE_UINT,
+               glu::TYPE_UINT_VEC2,
+               glu::TYPE_UINT_VEC3,
+               glu::TYPE_UINT_VEC4,
+               glu::TYPE_BOOL,
+               glu::TYPE_BOOL_VEC2,
+               glu::TYPE_BOOL_VEC3,
+               glu::TYPE_BOOL_VEC4,
+               glu::TYPE_FLOAT_MAT2,
+               glu::TYPE_FLOAT_MAT3,
+               glu::TYPE_FLOAT_MAT4,
+               glu::TYPE_FLOAT_MAT2X3,
+               glu::TYPE_FLOAT_MAT2X4,
+               glu::TYPE_FLOAT_MAT3X2,
+               glu::TYPE_FLOAT_MAT3X4,
+               glu::TYPE_FLOAT_MAT4X2,
+               glu::TYPE_FLOAT_MAT4X3
+       };
+
+       static const struct
+       {
+               const std::string       name;
+               deUint32                        flags;
+       } precisionFlags[] =
+       {
+               // TODO remove PRECISION_LOW because both PRECISION_LOW and PRECISION_MEDIUM means relaxed precision?
+               { "lowp",               PRECISION_LOW           },
+               { "mediump",    PRECISION_MEDIUM        },
+               { "highp",              PRECISION_HIGH          }
+       };
+
+       static const struct
+       {
+               const char*                     name;
+               deUint32                        flags;
+       } layoutFlags[] =
+       {
+               { "shared",             LAYOUT_SHARED   },
+               { "packed",             LAYOUT_PACKED   },
+               { "std140",             LAYOUT_STD140   }
+       };
+
+       static const struct
+       {
+               const std::string       name;
+               deUint32                        flags;
+       } matrixFlags[] =
+       {
+               { "row_major",          LAYOUT_ROW_MAJOR        },
+               { "column_major",       LAYOUT_COLUMN_MAJOR }
+       };
+
+       static const struct
+       {
+               const char*                                                     name;
+               UniformBlockCase::BufferMode            mode;
+       } bufferModes[] =
+       {
+               { "per_block_buffer",   UniformBlockCase::BUFFERMODE_PER_BLOCK },
+               { "single_buffer",              UniformBlockCase::BUFFERMODE_SINGLE     }
+       };
+
+       // ubo.2_level_array
+       {
+               tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array", "2-level basic array variable in single buffer");
+               addChild(nestedArrayGroup);
+
+               for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+               {
+                       tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
+                       nestedArrayGroup->addChild(layoutGroup);
+
+                       for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
+                       {
+                               const glu::DataType     type            = basicTypes[basicTypeNdx];
+                               const char*                     typeName        = glu::getDataTypeName(type);
+                               const int                       childSize       = 4;
+                               const int                       parentSize      = 3;
+                               const VarType           childType       (VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), childSize);
+                               const VarType           parentType      (childType, parentSize);
+
+                               createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
+
+                               if (glu::isDataTypeMatrix(type))
+                               {
+                                       for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
+                                               createBlockBasicTypeCases(layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
+                                                                                                 parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
+                               }
+                       }
+               }
+       }
+
+       // ubo.3_level_array
+       {
+               tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array", "3-level basic array variable in single buffer");
+               addChild(nestedArrayGroup);
+
+               for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+               {
+                       tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
+                       nestedArrayGroup->addChild(layoutGroup);
+
+                       for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
+                       {
+                               const glu::DataType     type            = basicTypes[basicTypeNdx];
+                               const char*                     typeName        = glu::getDataTypeName(type);
+                               const int                       childSize0      = 2;
+                               const int                       childSize1      = 4;
+                               const int                       parentSize      = 3;
+                               const VarType           childType0      (VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), childSize0);
+                               const VarType           childType1      (childType0, childSize1);
+                               const VarType           parentType      (childType1, parentSize);
+
+                               createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
+
+                               if (glu::isDataTypeMatrix(type))
+                               {
+                                       for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
+                                               createBlockBasicTypeCases(layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
+                                                                                                 parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
+                               }
+                       }
+               }
+       }
+
+       // ubo.2_level_struct_array
+       {
+               tcu::TestCaseGroup* structArrayArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_struct_array", "Struct array in one uniform block");
+               addChild(structArrayArrayGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       structArrayArrayGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
+                                               continue; // Doesn't make sense to add this variant.
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_vertex"),   "", baseFlags|DECLARE_VERTEX,                                   bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_fragment"), "", baseFlags|DECLARE_FRAGMENT,                                 bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_both"),     "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_basic_type
+       {
+               tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
+               addChild(singleBasicTypeGroup);
+
+               for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+               {
+                       tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
+                       singleBasicTypeGroup->addChild(layoutGroup);
+
+                       for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
+                       {
+                               glu::DataType   type            = basicTypes[basicTypeNdx];
+                               const char*             typeName        = glu::getDataTypeName(type);
+
+                               if (glu::isDataTypeBoolOrBVec(type))
+                                       createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, VarType(type, 0), layoutFlags[layoutFlagNdx].flags);
+                               else
+                               {
+                                       for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
+                                               createBlockBasicTypeCases(layoutGroup, m_testCtx, precisionFlags[precNdx].name + "_" + typeName,
+                                                                                                 VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags);
+                               }
+
+                               if (glu::isDataTypeMatrix(type))
+                               {
+                                       for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
+                                       {
+                                               for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
+                                                       createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + precisionFlags[precNdx].name + "_" + typeName,
+                                                                                                         VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_basic_array
+       {
+               tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
+               addChild(singleBasicArrayGroup);
+
+               for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+               {
+                       tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
+                       singleBasicArrayGroup->addChild(layoutGroup);
+
+                       for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
+                       {
+                               glu::DataType   type            = basicTypes[basicTypeNdx];
+                               const char*             typeName        = glu::getDataTypeName(type);
+                               const int               arraySize       = 3;
+
+                               createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName,
+                                                                                 VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize),
+                                                                                 layoutFlags[layoutFlagNdx].flags);
+
+                               if (glu::isDataTypeMatrix(type))
+                               {
+                                       for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
+                                               createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
+                                                                                                 VarType(VarType(type, PRECISION_HIGH), arraySize),
+                                                                                                 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_struct
+       {
+               tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
+               addChild(singleStructGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       singleStructGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
+                                               continue; // Doesn't make sense to add this variant.
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex",          "", baseFlags|DECLARE_VERTEX,                                   bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_fragment",        "", baseFlags|DECLARE_FRAGMENT,                                 bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_both",    "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_struct_array
+       {
+               tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
+               addChild(singleStructArrayGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       singleStructArrayGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
+                                               continue; // Doesn't make sense to add this variant.
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_vertex",             "", baseFlags|DECLARE_VERTEX,                                   bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_fragment",   "", baseFlags|DECLARE_FRAGMENT,                                 bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_both",       "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_nested_struct
+       {
+               tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
+               addChild(singleNestedStructGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       singleNestedStructGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
+                                               continue; // Doesn't make sense to add this variant.
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_vertex",    "", baseFlags|DECLARE_VERTEX,                                   bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_fragment",  "", baseFlags|DECLARE_FRAGMENT,                                 bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_both",      "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.single_nested_struct_array
+       {
+               tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
+               addChild(singleNestedStructArrayGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       singleNestedStructArrayGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
+                                               continue; // Doesn't make sense to add this variant.
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_vertex",       "", baseFlags|DECLARE_VERTEX,                                   bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_fragment",     "", baseFlags|DECLARE_FRAGMENT,                                 bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_both", "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.instance_array_basic_type
+       {
+               tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
+               addChild(instanceArrayBasicTypeGroup);
+
+               for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+               {
+                       tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
+                       instanceArrayBasicTypeGroup->addChild(layoutGroup);
+
+                       for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
+                       {
+                               glu::DataType   type                    = basicTypes[basicTypeNdx];
+                               const char*             typeName                = glu::getDataTypeName(type);
+                               const int               numInstances    = 3;
+
+                               createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName,
+                                                                                 VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH),
+                                                                                 layoutFlags[layoutFlagNdx].flags, numInstances);
+
+                               if (glu::isDataTypeMatrix(type))
+                               {
+                                       for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
+                                               createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
+                                                                                                 VarType(type, PRECISION_HIGH), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
+                                                                                                 numInstances);
+                               }
+                       }
+               }
+       }
+
+       // ubo.multi_basic_types
+       {
+               tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
+               addChild(multiBasicTypesGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       multiBasicTypesGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex",       "", baseFlags|DECLARE_VERTEX,                                   baseFlags|DECLARE_VERTEX,                                       bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_fragment",     "", baseFlags|DECLARE_FRAGMENT,                                 baseFlags|DECLARE_FRAGMENT,                                     bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_both", "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,      bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_mixed",        "", baseFlags|DECLARE_VERTEX,                                   baseFlags|DECLARE_FRAGMENT,                                     bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.multi_nested_struct
+       {
+               tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
+               addChild(multiNestedStructGroup);
+
+               for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
+               {
+                       tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
+                       multiNestedStructGroup->addChild(modeGroup);
+
+                       for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
+                       {
+                               for (int isArray = 0; isArray < 2; isArray++)
+                               {
+                                       std::string     baseName        = layoutFlags[layoutFlagNdx].name;
+                                       deUint32        baseFlags       = layoutFlags[layoutFlagNdx].flags;
+
+                                       if (isArray)
+                                               baseName += "_instance_array";
+
+                                       modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex",             "", baseFlags|DECLARE_VERTEX,                                   baseFlags|DECLARE_VERTEX,                                       bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                                       modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_fragment",   "", baseFlags|DECLARE_FRAGMENT,                                 baseFlags|DECLARE_FRAGMENT,                                     bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       if (!(baseFlags & LAYOUT_PACKED))
+                                               modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_both",       "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,  baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,      bufferModes[modeNdx].mode, isArray ? 3 : 0));
+
+                                       modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_mixed",              "", baseFlags|DECLARE_VERTEX,                                   baseFlags|DECLARE_FRAGMENT,                                     bufferModes[modeNdx].mode, isArray ? 3 : 0));
+                               }
+                       }
+               }
+       }
+
+       // ubo.random
+       {
+               const deUint32  allShaders              = FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;
+               const deUint32  allLayouts              = FEATURE_PACKED_LAYOUT|FEATURE_SHARED_LAYOUT|FEATURE_STD140_LAYOUT;
+               const deUint32  allBasicTypes   = FEATURE_VECTORS|FEATURE_MATRICES;
+               const deUint32  unused                  = FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_UNIFORMS;
+               const deUint32  matFlags                = FEATURE_MATRIX_LAYOUT;
+               const deUint32  allFeatures             = ~FEATURE_ARRAYS_OF_ARRAYS;
+
+               tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
+               addChild(randomGroup);
+
+               // Basic types.
+               createRandomCaseGroup(randomGroup, m_testCtx, "scalar_types",   "Scalar types only, per-block buffers",                         UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused,                                                                           25, 0);
+               createRandomCaseGroup(randomGroup, m_testCtx, "vector_types",   "Scalar and vector types only, per-block buffers",      UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|FEATURE_VECTORS,                                           25, 25);
+               createRandomCaseGroup(randomGroup, m_testCtx, "basic_types",    "All basic types, per-block buffers",                           UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags,                            25, 50);
+               createRandomCaseGroup(randomGroup, m_testCtx, "basic_arrays",   "Arrays, per-block buffers",                                            UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,     25, 50);
+
+               createRandomCaseGroup(randomGroup, m_testCtx, "basic_instance_arrays",                                  "Basic instance arrays, per-block buffers",                             UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_INSTANCE_ARRAYS,                                                            25, 75);
+               createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs",                                                 "Nested structs, per-block buffers",                                    UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS,                                                                            25, 100);
+               createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays",                                  "Nested structs, arrays, per-block buffers",                    UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS,                                                     25, 150);
+               createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_instance_arrays",                 "Nested structs, instance arrays, per-block buffers",   UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,                            25, 125);
+               createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays_instance_arrays",  "Nested structs, instance arrays, per-block buffers",   UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_INSTANCE_ARRAYS,     25, 175);
+
+               createRandomCaseGroup(randomGroup, m_testCtx, "all_per_block_buffers",  "All random features, per-block buffers",       UniformBlockCase::BUFFERMODE_PER_BLOCK, allFeatures,    50, 200);
+               createRandomCaseGroup(randomGroup, m_testCtx, "all_shared_buffer",              "All random features, shared buffer",           UniformBlockCase::BUFFERMODE_SINGLE,    allFeatures,    50, 250);
+       }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup*    createTests     (tcu::TestContext& testCtx)
+{
+       return new UniformBlockTests(testCtx);
+}
+
+} // ubo
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.hpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.hpp
new file mode 100644 (file)
index 0000000..b571323
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _VKTUNIFORMBUFFERTESTS_HPP
+#define _VKTUNIFORMBUFFERTESTS_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 Uniform block tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace ubo
+{
+
+tcu::TestCaseGroup*            createTests             (tcu::TestContext& testCtx);
+
+} // ubo
+} // vkt
+
+#endif // _VKTUNIFORMBUFFERTESTS_HPP
index 0109cf7..e60d6d9 100644 (file)
@@ -63,6 +63,7 @@
 #include "vktShaderRenderStructTests.hpp"
 #include "vktShaderRenderSwitchTests.hpp"
 #include "vktShaderExecutorTests.hpp"
+#include "vktUniformBlockTests.hpp"
 
 #include <vector>
 #include <sstream>
@@ -311,6 +312,7 @@ void TestPackage::init (void)
        addChild(createGlslTests                        (m_testCtx));
        addChild(createRenderPassTests          (m_testCtx));
        addChild(memory::createTests            (m_testCtx));
+       addChild(ubo::createTests                       (m_testCtx));
 }
 
 } // vkt