Merge 42-ubo
authorPyry Haulos <phaulos@google.com>
Thu, 17 Dec 2015 23:38:18 +0000 (15:38 -0800)
committerPyry Haulos <phaulos@google.com>
Thu, 17 Dec 2015 23:38:18 +0000 (15:38 -0800)
60 files changed:
Android.mk
doc/testspecs/VK/apitests.adoc
external/fetch_sources.py
external/vulkancts/framework/vulkan/CMakeLists.txt
external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.cpp [new file with mode: 0644]
external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.hpp [new file with mode: 0644]
external/vulkancts/framework/vulkan/vkGlslToSpirV.cpp
external/vulkancts/framework/vulkan/vkImageUtil.cpp
external/vulkancts/framework/vulkan/vkImageUtil.hpp
external/vulkancts/framework/vulkan/vkNullDriver.cpp
external/vulkancts/framework/vulkan/vkNullDriverImpl.inl
external/vulkancts/framework/vulkan/vkQueryUtil.hpp
external/vulkancts/gen_framework.py
external/vulkancts/modules/vulkan/CMakeLists.txt
external/vulkancts/modules/vulkan/api/CMakeLists.txt
external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
external/vulkancts/modules/vulkan/api/vktApiBufferViewAccessTests.cpp
external/vulkancts/modules/vulkan/api/vktApiBufferViewCreateTests.cpp
external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.cpp
external/vulkancts/modules/vulkan/api/vktApiFeatureInfo.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/api/vktApiFeatureInfo.hpp [moved from external/vulkancts/modules/vulkan/vktInfo.hpp with 87% similarity]
external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.cpp
external/vulkancts/modules/vulkan/api/vktApiTests.cpp
external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.cpp
external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt
external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineCombinationsIterator.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineImageSamplingInstance.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.hpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineSamplerTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.hpp
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderBuiltinPrecisionTests.cpp
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp
external/vulkancts/modules/vulkan/shaderrender/vktShaderRender.cpp
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderMatrixTests.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
external/vulkancts/modules/vulkan/vktInfo.cpp [deleted file]
external/vulkancts/modules/vulkan/vktRenderPassTests.cpp
external/vulkancts/modules/vulkan/vktTestPackage.cpp
framework/delibs/debase/deInt32.h
framework/delibs/debase/deMemory.c
framework/delibs/debase/deMemory.h
framework/delibs/decpp/CMakeLists.txt
framework/delibs/decpp/deAppendList.cpp [new file with mode: 0644]
framework/delibs/decpp/deAppendList.hpp [new file with mode: 0644]
framework/delibs/decpp/deDefs.hpp
modules/internal/ditDelibsTests.cpp

index 1619790..ba09272 100644 (file)
@@ -81,6 +81,7 @@ LOCAL_SRC_FILES := \
        framework/delibs/debase/deRandom.c \
        framework/delibs/debase/deString.c \
        framework/delibs/debase/deSha1.c \
+       framework/delibs/decpp/deAppendList.cpp \
        framework/delibs/decpp/deArrayBuffer.cpp \
        framework/delibs/decpp/deArrayUtil.cpp \
        framework/delibs/decpp/deBlockBuffer.cpp \
index 8db7021..bbc2a70 100644 (file)
@@ -2723,8 +2723,6 @@ void VKAPI vkCmdResolveImage(
 Push constants
 --------------
 
-TODO
-
 [source,c]
 ----
 void VKAPI vkCmdPushConstants(
@@ -2736,6 +2734,12 @@ void VKAPI vkCmdPushConstants(
     const void*                                 values);
 ----
 
+ * Range size, including verify various size of a single range from minimum to maximum
+ * Range count, including verify all the valid shader stages
+ * Data update, including verify a sub-range update, multiple times of updates
+ ? Invalid usages specified in spec NOT tested
+
 GPU timestamps
 --------------
 
index 437ce68..46de4d2 100644 (file)
@@ -134,10 +134,11 @@ class SourcePackage (Source):
                        self.postExtract(dstPath)
 
 class GitRepo (Source):
-       def __init__(self, url, revision, baseDir, extractDir = "src"):
+       def __init__(self, url, revision, baseDir, extractDir = "src", postCheckout = None):
                Source.__init__(self, baseDir, extractDir)
-               self.url                = url
-               self.revision   = revision
+               self.url                        = url
+               self.revision           = revision
+               self.postCheckout       = postCheckout
 
        def update (self):
                fullDstPath = os.path.join(EXTERNAL_DIR, self.baseDir, self.extractDir)
@@ -149,6 +150,9 @@ class GitRepo (Source):
                try:
                        execute(["git", "fetch", self.url, "+refs/heads/*:refs/remotes/origin/*"])
                        execute(["git", "checkout", self.revision])
+
+                       if self.postCheckout:
+                               self.postCheckout(fullDstPath)
                finally:
                        popWorkingDir()
 
@@ -156,6 +160,12 @@ def postExtractLibpng (path):
        shutil.copy(os.path.join(path, "scripts", "pnglibconf.h.prebuilt"),
                                os.path.join(path, "pnglibconf.h"))
 
+def postCheckoutGlslang (path):
+       srcPath = os.path.join(path, "SPIRV", "SpvBuilder.cpp");
+       origSrc = readFile(srcPath)
+       patched = origSrc.replace("exit(1)", "throw std::runtime_error(fun)")
+       writeFile(srcPath, patched)
+
 PACKAGES = [
        SourcePackage(
                "http://zlib.net/zlib-1.2.8.tar.gz",
@@ -174,8 +184,9 @@ PACKAGES = [
                "spirv-tools"),
        GitRepo(
                "git@gitlab.khronos.org:GLSL/glslang.git",
-               "9e1d1465801ace8edd95c951a3d4a9ada75306ed",
-               "glslang"),
+               "41daec718f4868d956ca7d339a15aebe65879442",
+               "glslang",
+               postCheckout = postCheckoutGlslang),
 ]
 
 def parseArgs ():
index b765088..9f76ec3 100644 (file)
@@ -37,6 +37,8 @@ set(VKUTIL_SRCS
        vkImageUtil.hpp
        vkTypeUtil.cpp
        vkTypeUtil.hpp
+       vkAllocationCallbackUtil.cpp
+       vkAllocationCallbackUtil.hpp
        )
 
 set(VKUTIL_LIBS
diff --git a/external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.cpp b/external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.cpp
new file mode 100644 (file)
index 0000000..ec748af
--- /dev/null
@@ -0,0 +1,720 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * 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 Memory allocation callback utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkAllocationCallbackUtil.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuTestLog.hpp"
+#include "deSTLUtil.hpp"
+#include "deMemory.h"
+
+#include <map>
+
+namespace vk
+{
+
+// System default allocator
+
+static VKAPI_ATTR void* VKAPI_CALL systemAllocate (void*, size_t size, size_t alignment, VkSystemAllocationScope)
+{
+       if (size > 0)
+               return deAlignedMalloc(size, (deUint32)alignment);
+       else
+               return DE_NULL;
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemFree (void*, void* pMem)
+{
+       deAlignedFree(pMem);
+}
+
+static VKAPI_ATTR void* VKAPI_CALL systemReallocate (void*, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope)
+{
+       return deAlignedRealloc(pOriginal, size, alignment);
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemInternalAllocationNotification (void*, size_t, VkInternalAllocationType, VkSystemAllocationScope)
+{
+}
+
+static VKAPI_ATTR void VKAPI_CALL systemInternalFreeNotification (void*, size_t, VkInternalAllocationType, VkSystemAllocationScope)
+{
+}
+
+static const VkAllocationCallbacks s_systemAllocator =
+{
+       DE_NULL,                // pUserData
+       systemAllocate,
+       systemReallocate,
+       systemFree,
+       systemInternalAllocationNotification,
+       systemInternalFreeNotification,
+};
+
+const VkAllocationCallbacks* getSystemAllocator (void)
+{
+       return &s_systemAllocator;
+}
+
+// AllocationCallbacks
+
+static VKAPI_ATTR void* VKAPI_CALL allocationCallback (void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       return reinterpret_cast<AllocationCallbacks*>(pUserData)->allocate(size, alignment, allocationScope);
+}
+
+static VKAPI_ATTR void* VKAPI_CALL reallocationCallback (void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       return reinterpret_cast<AllocationCallbacks*>(pUserData)->reallocate(pOriginal, size, alignment, allocationScope);
+}
+
+static VKAPI_ATTR void VKAPI_CALL freeCallback (void* pUserData, void* pMem)
+{
+       reinterpret_cast<AllocationCallbacks*>(pUserData)->free(pMem);
+}
+
+static VKAPI_ATTR void VKAPI_CALL internalAllocationNotificationCallback (void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       reinterpret_cast<AllocationCallbacks*>(pUserData)->notifyInternalAllocation(size, allocationType, allocationScope);
+}
+
+static VKAPI_ATTR void VKAPI_CALL internalFreeNotificationCallback (void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       reinterpret_cast<AllocationCallbacks*>(pUserData)->notifyInternalFree(size, allocationType, allocationScope);
+}
+
+static VkAllocationCallbacks makeCallbacks (AllocationCallbacks* object)
+{
+       const VkAllocationCallbacks callbacks =
+       {
+               reinterpret_cast<void*>(object),
+               allocationCallback,
+               reallocationCallback,
+               freeCallback,
+               internalAllocationNotificationCallback,
+               internalFreeNotificationCallback
+       };
+       return callbacks;
+}
+
+AllocationCallbacks::AllocationCallbacks (void)
+       : m_callbacks(makeCallbacks(this))
+{
+}
+
+AllocationCallbacks::~AllocationCallbacks (void)
+{
+}
+
+// AllocationCallbackRecord
+
+AllocationCallbackRecord AllocationCallbackRecord::allocation (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr)
+{
+       AllocationCallbackRecord record;
+
+       record.type                                                     = TYPE_ALLOCATION;
+       record.data.allocation.size                     = size;
+       record.data.allocation.alignment        = alignment;
+       record.data.allocation.scope            = scope;
+       record.data.allocation.returnedPtr      = returnedPtr;
+
+       return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::reallocation (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr)
+{
+       AllocationCallbackRecord record;
+
+       record.type                                                             = TYPE_REALLOCATION;
+       record.data.reallocation.original               = original;
+       record.data.reallocation.size                   = size;
+       record.data.reallocation.alignment              = alignment;
+       record.data.reallocation.scope                  = scope;
+       record.data.reallocation.returnedPtr    = returnedPtr;
+
+       return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::free (void* mem)
+{
+       AllocationCallbackRecord record;
+
+       record.type                             = TYPE_FREE;
+       record.data.free.mem    = mem;
+
+       return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::internalAllocation (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope)
+{
+       AllocationCallbackRecord record;
+
+       record.type                                                             = TYPE_INTERNAL_ALLOCATION;
+       record.data.internalAllocation.size             = size;
+       record.data.internalAllocation.type             = type;
+       record.data.internalAllocation.scope    = scope;
+
+       return record;
+}
+
+AllocationCallbackRecord AllocationCallbackRecord::internalFree (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope)
+{
+       AllocationCallbackRecord record;
+
+       record.type                                                             = TYPE_INTERNAL_FREE;
+       record.data.internalAllocation.size             = size;
+       record.data.internalAllocation.type             = type;
+       record.data.internalAllocation.scope    = scope;
+
+       return record;
+}
+
+// ChainedAllocator
+
+ChainedAllocator::ChainedAllocator (const VkAllocationCallbacks* nextAllocator)
+       : m_nextAllocator(nextAllocator)
+{
+}
+
+ChainedAllocator::~ChainedAllocator (void)
+{
+}
+
+void* ChainedAllocator::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       return m_nextAllocator->pfnAllocation(m_nextAllocator->pUserData, size, alignment, allocationScope);
+}
+
+void* ChainedAllocator::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       return m_nextAllocator->pfnReallocation(m_nextAllocator->pUserData, original, size, alignment, allocationScope);
+}
+
+void ChainedAllocator::free (void* mem)
+{
+       m_nextAllocator->pfnFree(m_nextAllocator->pUserData, mem);
+}
+
+void ChainedAllocator::notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       m_nextAllocator->pfnInternalAllocation(m_nextAllocator->pUserData, size, allocationType, allocationScope);
+}
+
+void ChainedAllocator::notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       m_nextAllocator->pfnInternalFree(m_nextAllocator->pUserData, size, allocationType, allocationScope);
+}
+
+// AllocationCallbackRecorder
+
+AllocationCallbackRecorder::AllocationCallbackRecorder (const VkAllocationCallbacks* allocator, deUint32 callCountHint)
+       : ChainedAllocator      (allocator)
+       , m_records                     (callCountHint)
+{
+}
+
+AllocationCallbackRecorder::~AllocationCallbackRecorder (void)
+{
+}
+
+void* AllocationCallbackRecorder::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       void* const     ptr     = ChainedAllocator::allocate(size, alignment, allocationScope);
+
+       m_records.append(AllocationCallbackRecord::allocation(size, alignment, allocationScope, ptr));
+
+       return ptr;
+}
+
+void* AllocationCallbackRecorder::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       void* const     ptr     = ChainedAllocator::reallocate(original, size, alignment, allocationScope);
+
+       m_records.append(AllocationCallbackRecord::reallocation(original, size, alignment, allocationScope, ptr));
+
+       return ptr;
+}
+
+void AllocationCallbackRecorder::free (void* mem)
+{
+       ChainedAllocator::free(mem);
+
+       m_records.append(AllocationCallbackRecord::free(mem));
+}
+
+void AllocationCallbackRecorder::notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       ChainedAllocator::notifyInternalAllocation(size, allocationType, allocationScope);
+
+       m_records.append(AllocationCallbackRecord::internalAllocation(size, allocationType, allocationScope));
+}
+
+void AllocationCallbackRecorder::notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+       ChainedAllocator::notifyInternalFree(size, allocationType, allocationScope);
+
+       m_records.append(AllocationCallbackRecord::internalFree(size, allocationType, allocationScope));
+}
+
+// DeterministicFailAllocator
+
+DeterministicFailAllocator::DeterministicFailAllocator (const VkAllocationCallbacks* allocator, deUint32 numPassingAllocs)
+       : ChainedAllocator      (allocator)
+       , m_numPassingAllocs(numPassingAllocs)
+       , m_allocationNdx       (0)
+{
+}
+
+DeterministicFailAllocator::~DeterministicFailAllocator (void)
+{
+}
+
+void* DeterministicFailAllocator::allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       if (deAtomicIncrementUint32(&m_allocationNdx) <= m_numPassingAllocs)
+               return ChainedAllocator::allocate(size, alignment, allocationScope);
+       else
+               return DE_NULL;
+}
+
+void* DeterministicFailAllocator::reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+       if (deAtomicIncrementUint32(&m_allocationNdx) <= m_numPassingAllocs)
+               return ChainedAllocator::reallocate(original, size, alignment, allocationScope);
+       else
+               return DE_NULL;
+}
+
+// Utils
+
+AllocationCallbackValidationResults::AllocationCallbackValidationResults (void)
+{
+       deMemset(internalAllocationTotal, 0, sizeof(internalAllocationTotal));
+}
+
+void AllocationCallbackValidationResults::clear (void)
+{
+       liveAllocations.clear();
+       violations.clear();
+       deMemset(internalAllocationTotal, 0, sizeof(internalAllocationTotal));
+}
+
+namespace
+{
+
+struct AllocationSlot
+{
+       AllocationCallbackRecord        record;
+       bool                                            isLive;
+
+       AllocationSlot (void)
+               : isLive        (false)
+       {}
+
+       AllocationSlot (const AllocationCallbackRecord& record_, bool isLive_)
+               : record        (record_)
+               , isLive        (isLive_)
+       {}
+};
+
+size_t getAlignment (const AllocationCallbackRecord& record)
+{
+       if (record.type == AllocationCallbackRecord::TYPE_ALLOCATION)
+               return record.data.allocation.alignment;
+       else if (record.type == AllocationCallbackRecord::TYPE_REALLOCATION)
+               return record.data.reallocation.alignment;
+       else
+       {
+               DE_ASSERT(false);
+               return 0;
+       }
+}
+
+} // anonymous
+
+void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results)
+{
+       std::vector<AllocationSlot>             allocations;
+       std::map<void*, size_t>                 ptrToSlotIndex;
+
+       DE_ASSERT(results->liveAllocations.empty() && results->violations.empty());
+
+       for (AllocationCallbackRecorder::RecordIterator callbackIter = recorder.getRecordsBegin();
+                callbackIter != recorder.getRecordsEnd();
+                ++callbackIter)
+       {
+               const AllocationCallbackRecord&         record  = *callbackIter;
+
+               // Validate scope
+               {
+                       const VkSystemAllocationScope* const    scopePtr        = record.type == AllocationCallbackRecord::TYPE_ALLOCATION                      ? &record.data.allocation.scope
+                                                                                                                               : record.type == AllocationCallbackRecord::TYPE_REALLOCATION            ? &record.data.reallocation.scope
+                                                                                                                               : record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION     ? &record.data.internalAllocation.scope
+                                                                                                                               : record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE           ? &record.data.internalAllocation.scope
+                                                                                                                               : DE_NULL;
+
+                       if (scopePtr && !de::inBounds(*scopePtr, (VkSystemAllocationScope)0, VK_SYSTEM_ALLOCATION_SCOPE_LAST))
+                               results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_ALLOCATION_SCOPE));
+               }
+
+               // Validate alignment
+               if (record.type == AllocationCallbackRecord::TYPE_ALLOCATION ||
+                       record.type == AllocationCallbackRecord::TYPE_REALLOCATION)
+               {
+                       if (!deIsPowerOfTwoSize(getAlignment(record)))
+                               results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_ALIGNMENT));
+               }
+
+               // Validate actual allocation behavior
+               switch (record.type)
+               {
+                       case AllocationCallbackRecord::TYPE_ALLOCATION:
+                       {
+                               DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.allocation.returnedPtr));
+
+                               if (record.data.allocation.returnedPtr)
+                               {
+                                       ptrToSlotIndex[record.data.allocation.returnedPtr] = allocations.size();
+                                       allocations.push_back(AllocationSlot(record, true));
+                               }
+
+                               break;
+                       }
+
+                       case AllocationCallbackRecord::TYPE_REALLOCATION:
+                       {
+                               if (de::contains(ptrToSlotIndex, record.data.reallocation.original))
+                               {
+                                       const size_t            origSlotNdx             = ptrToSlotIndex[record.data.reallocation.original];
+                                       AllocationSlot&         origSlot                = allocations[origSlotNdx];
+
+                                       DE_ASSERT(record.data.reallocation.original != DE_NULL);
+
+                                       if (record.data.reallocation.size > 0)
+                                       {
+                                               if (getAlignment(origSlot.record) != record.data.reallocation.alignment)
+                                                       results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_DIFFERENT_ALIGNMENT));
+
+                                               if (record.data.reallocation.original == record.data.reallocation.returnedPtr)
+                                               {
+                                                       if (!origSlot.isLive)
+                                                       {
+                                                               results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_FREED_PTR));
+                                                               origSlot.isLive = true; // Mark live to suppress further errors
+                                                       }
+
+                                                       // Just update slot record
+                                                       allocations[origSlotNdx].record = record;
+                                               }
+                                               else
+                                               {
+                                                       DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.reallocation.returnedPtr));
+
+                                                       if (record.data.reallocation.returnedPtr)
+                                                       {
+                                                               allocations[origSlotNdx].isLive = false;
+                                                               ptrToSlotIndex[record.data.reallocation.returnedPtr] = allocations.size();
+                                                               allocations.push_back(AllocationSlot(record, true));
+                                                       }
+                                                       // else original ptr remains valid and live
+                                               }
+                                       }
+                                       else
+                                       {
+                                               DE_ASSERT(!record.data.reallocation.returnedPtr);
+
+                                               origSlot.isLive = false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (record.data.reallocation.original)
+                                               results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_REALLOC_NOT_ALLOCATED_PTR));
+
+                                       if (record.data.reallocation.returnedPtr)
+                                       {
+                                               DE_ASSERT(!de::contains(ptrToSlotIndex, record.data.reallocation.returnedPtr));
+                                               ptrToSlotIndex[record.data.reallocation.returnedPtr] = allocations.size();
+                                               allocations.push_back(AllocationSlot(record, true));
+                                       }
+                               }
+
+                               break;
+                       }
+
+                       case AllocationCallbackRecord::TYPE_FREE:
+                       {
+                               if (record.data.free.mem != DE_NULL) // Freeing null pointer is valid and ignored
+                               {
+                                       if (de::contains(ptrToSlotIndex, record.data.free.mem))
+                                       {
+                                               const size_t    slotNdx         = ptrToSlotIndex[record.data.free.mem];
+
+                                               if (allocations[slotNdx].isLive)
+                                                       allocations[slotNdx].isLive = false;
+                                               else
+                                                       results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_DOUBLE_FREE));
+                                       }
+                                       else
+                                               results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_FREE_NOT_ALLOCATED_PTR));
+                               }
+
+                               break;
+                       }
+
+                       case AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION:
+                       case AllocationCallbackRecord::TYPE_INTERNAL_FREE:
+                       {
+                               if (de::inBounds(record.data.internalAllocation.type, (VkInternalAllocationType)0, VK_INTERNAL_ALLOCATION_TYPE_LAST))
+                               {
+                                       size_t* const           totalAllocSizePtr       = &results->internalAllocationTotal[record.data.internalAllocation.type][record.data.internalAllocation.scope];
+                                       const size_t            size                            = record.data.internalAllocation.size;
+
+                                       if (record.type == AllocationCallbackRecord::TYPE_FREE)
+                                       {
+                                               if (*totalAllocSizePtr < size)
+                                               {
+                                                       results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL));
+                                                       *totalAllocSizePtr = 0; // Reset to 0 to suppress compound errors
+                                               }
+                                               else
+                                                       *totalAllocSizePtr -= size;
+                                       }
+                                       else
+                                               *totalAllocSizePtr += size;
+                               }
+                               else
+                                       results->violations.push_back(AllocationCallbackViolation(record, AllocationCallbackViolation::REASON_INVALID_INTERNAL_ALLOCATION_TYPE));
+
+                               break;
+                       }
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+
+       DE_ASSERT(!de::contains(ptrToSlotIndex, DE_NULL));
+
+       // Collect live allocations
+       for (std::vector<AllocationSlot>::const_iterator slotIter = allocations.begin();
+                slotIter != allocations.end();
+                ++slotIter)
+       {
+               if (slotIter->isLive)
+                       results->liveAllocations.push_back(slotIter->record);
+       }
+}
+
+bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits)
+{
+       using tcu::TestLog;
+
+       size_t  numLeaks        = 0;
+
+       if (!results.violations.empty())
+       {
+               for (size_t violationNdx = 0; violationNdx < results.violations.size(); ++violationNdx)
+               {
+                       log << TestLog::Message << "VIOLATION " << (violationNdx+1)
+                                                                                                       << ": " << results.violations[violationNdx]
+                                                                                                       << " (" << results.violations[violationNdx].record << ")"
+                               << TestLog::EndMessage;
+               }
+
+               log << TestLog::Message << "ERROR: Found " << results.violations.size() << " invalid allocation callbacks!" << TestLog::EndMessage;
+       }
+
+       // Verify live allocations
+       for (size_t liveNdx = 0; liveNdx < results.liveAllocations.size(); ++liveNdx)
+       {
+               const AllocationCallbackRecord&         record  = results.liveAllocations[liveNdx];
+               const VkSystemAllocationScope           scope   = record.type == AllocationCallbackRecord::TYPE_ALLOCATION              ? record.data.allocation.scope
+                                                                                                       : record.type == AllocationCallbackRecord::TYPE_REALLOCATION    ? record.data.reallocation.scope
+                                                                                                       : VK_SYSTEM_ALLOCATION_SCOPE_LAST;
+
+               DE_ASSERT(de::inBounds(scope, (VkSystemAllocationScope)0, VK_SYSTEM_ALLOCATION_SCOPE_LAST));
+
+               if ((allowedLiveAllocScopeBits & (1u << scope)) == 0)
+               {
+                       log << TestLog::Message << "LEAK " << (numLeaks+1) << ": " << record << TestLog::EndMessage;
+                       numLeaks += 1;
+               }
+       }
+
+       // Verify internal allocations
+       for (int internalAllocTypeNdx = 0; internalAllocTypeNdx < VK_INTERNAL_ALLOCATION_TYPE_LAST; ++internalAllocTypeNdx)
+       {
+               for (int scopeNdx = 0; scopeNdx < VK_SYSTEM_ALLOCATION_SCOPE_LAST; ++scopeNdx)
+               {
+                       const VkInternalAllocationType  type                    = (VkInternalAllocationType)internalAllocTypeNdx;
+                       const VkSystemAllocationScope   scope                   = (VkSystemAllocationScope)scopeNdx;
+                       const size_t                                    totalAllocated  = results.internalAllocationTotal[type][scope];
+
+                       if ((allowedLiveAllocScopeBits & (1u << scopeNdx)) == 0 &&
+                               totalAllocated > 0)
+                       {
+                               log << TestLog::Message << "LEAK " << (numLeaks+1) << ": " << totalAllocated
+                                                                               << " bytes of (" << type << ", " << scope << ") internal memory is still allocated"
+                                       << TestLog::EndMessage;
+                               numLeaks += 1;
+                       }
+               }
+       }
+
+       if (numLeaks > 0)
+               log << TestLog::Message << "ERROR: Found " << numLeaks << " memory leaks!" << TestLog::EndMessage;
+
+       return results.violations.empty() && numLeaks == 0;
+}
+
+bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits)
+{
+       AllocationCallbackValidationResults     validationResults;
+
+       validateAllocationCallbacks(recorder, &validationResults);
+
+       return checkAndLog(log, validationResults, allowedLiveAllocScopeBits);
+}
+
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record)
+{
+       switch (record.type)
+       {
+               case AllocationCallbackRecord::TYPE_ALLOCATION:
+                       str << "ALLOCATION: size=" << record.data.allocation.size
+                               << ", alignment=" << record.data.allocation.alignment
+                               << ", scope=" << record.data.allocation.scope
+                               << ", returnedPtr=" << tcu::toHex(record.data.allocation.returnedPtr);
+                       break;
+
+               case AllocationCallbackRecord::TYPE_REALLOCATION:
+                       str << "REALLOCATION: original=" << tcu::toHex(record.data.reallocation.original)
+                               << ", size=" << record.data.reallocation.size
+                               << ", alignment=" << record.data.reallocation.alignment
+                               << ", scope=" << record.data.reallocation.scope
+                               << ", returnedPtr=" << tcu::toHex(record.data.reallocation.returnedPtr);
+                       break;
+
+               case AllocationCallbackRecord::TYPE_FREE:
+                       str << "FREE: mem=" << tcu::toHex(record.data.free.mem);
+                       break;
+
+               case AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION:
+               case AllocationCallbackRecord::TYPE_INTERNAL_FREE:
+                       str << "INTERNAL_" << (record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION ? "ALLOCATION" : "FREE")
+                               << ": size=" << record.data.internalAllocation.size
+                               << ", type=" << record.data.internalAllocation.type
+                               << ", scope=" << record.data.internalAllocation.scope;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       return str;
+}
+
+std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation)
+{
+       switch (violation.reason)
+       {
+               case AllocationCallbackViolation::REASON_DOUBLE_FREE:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_FREE);
+                       str << "Double free of " << tcu::toHex(violation.record.data.free.mem);
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_FREE_NOT_ALLOCATED_PTR:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_FREE);
+                       str << "Attempt to free " << tcu::toHex(violation.record.data.free.mem) << " which has not been allocated";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_REALLOC_NOT_ALLOCATED_PTR:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_REALLOCATION);
+                       str << "Attempt to reallocate " << tcu::toHex(violation.record.data.reallocation.original) << " which has not been allocated";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_REALLOC_FREED_PTR:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_REALLOCATION);
+                       str << "Attempt to reallocate " << tcu::toHex(violation.record.data.reallocation.original) << " which has been freed";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE);
+                       str << "Internal allocation total for (" << violation.record.data.internalAllocation.type << ", " << violation.record.data.internalAllocation.scope << ") is negative";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_INVALID_INTERNAL_ALLOCATION_TYPE:
+               {
+                       DE_ASSERT(violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_ALLOCATION ||
+                                         violation.record.type == AllocationCallbackRecord::TYPE_INTERNAL_FREE);
+                       str << "Invalid internal allocation type " << tcu::toHex(violation.record.data.internalAllocation.type);
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_INVALID_ALLOCATION_SCOPE:
+               {
+                       str << "Invalid allocation scope";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_INVALID_ALIGNMENT:
+               {
+                       str << "Invalid alignment";
+                       break;
+               }
+
+               case AllocationCallbackViolation::REASON_REALLOC_DIFFERENT_ALIGNMENT:
+               {
+                       str << "Reallocation with different alignment";
+                       break;
+               }
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       return str;
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.hpp b/external/vulkancts/framework/vulkan/vkAllocationCallbackUtil.hpp
new file mode 100644 (file)
index 0000000..057dc7e
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef _VKALLOCATIONCALLBACKUTIL_HPP
+#define _VKALLOCATIONCALLBACKUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * 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 Memory allocation callback utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "deAppendList.hpp"
+
+#include <vector>
+#include <ostream>
+
+namespace tcu
+{
+class TestLog;
+}
+
+namespace vk
+{
+
+class AllocationCallbacks
+{
+public:
+                                                                       AllocationCallbacks             (void);
+       virtual                                                 ~AllocationCallbacks    (void);
+
+       virtual void*                                   allocate                                (size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
+       virtual void*                                   reallocate                              (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
+       virtual void                                    free                                    (void* mem) = 0;
+
+       virtual void                                    notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
+       virtual void                                    notifyInternalFree              (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
+
+       const VkAllocationCallbacks*    getCallbacks                    (void) const { return &m_callbacks;     }
+
+private:
+       const VkAllocationCallbacks             m_callbacks;
+};
+
+struct AllocationCallbackRecord
+{
+       enum Type
+       {
+               TYPE_ALLOCATION         = 0,            //! Call to pfnAllocation
+               TYPE_REALLOCATION,                              //! Call to pfnReallocation
+               TYPE_FREE,                                              //! Call to pfnFree
+               TYPE_INTERNAL_ALLOCATION,               //! Call to pfnInternalAllocation
+               TYPE_INTERNAL_FREE,                             //! Call to pfnInternalFree
+
+               TYPE_LAST
+       };
+
+       Type    type;
+
+       union
+       {
+               struct
+               {
+                       size_t                                          size;
+                       size_t                                          alignment;
+                       VkSystemAllocationScope         scope;
+                       void*                                           returnedPtr;
+               } allocation;
+
+               struct
+               {
+                       void*                                           original;
+                       size_t                                          size;
+                       size_t                                          alignment;
+                       VkSystemAllocationScope         scope;
+                       void*                                           returnedPtr;
+               } reallocation;
+
+               struct
+               {
+                       void*                                           mem;
+               } free;
+
+               // \note Used for both INTERNAL_ALLOCATION and INTERNAL_FREE
+               struct
+               {
+                       size_t                                          size;
+                       VkInternalAllocationType        type;
+                       VkSystemAllocationScope         scope;
+               } internalAllocation;
+       } data;
+
+                                                                       AllocationCallbackRecord        (void) : type(TYPE_LAST) {}
+
+       static AllocationCallbackRecord allocation                                      (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
+       static AllocationCallbackRecord reallocation                            (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
+       static AllocationCallbackRecord free                                            (void* mem);
+       static AllocationCallbackRecord internalAllocation                      (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
+       static AllocationCallbackRecord internalFree                            (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
+};
+
+class ChainedAllocator : public AllocationCallbacks
+{
+public:
+                                                                       ChainedAllocator                (const VkAllocationCallbacks* nextAllocator);
+                                                                       ~ChainedAllocator               (void);
+
+       void*                                                   allocate                                (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+       void*                                                   reallocate                              (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+       void                                                    free                                    (void* mem);
+
+       void                                                    notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+       void                                                    notifyInternalFree              (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+
+private:
+       const VkAllocationCallbacks*    m_nextAllocator;
+};
+
+class AllocationCallbackRecorder : public ChainedAllocator
+{
+public:
+                                                       AllocationCallbackRecorder      (const VkAllocationCallbacks* allocator, deUint32 callCountHint = 1024);
+                                                       ~AllocationCallbackRecorder     (void);
+
+       void*                                   allocate                                        (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+       void*                                   reallocate                                      (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+       void                                    free                                            (void* mem);
+
+       void                                    notifyInternalAllocation        (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+       void                                    notifyInternalFree                      (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+
+       typedef de::AppendList<AllocationCallbackRecord>::const_iterator        RecordIterator;
+
+       RecordIterator                  getRecordsBegin                         (void) const { return m_records.begin();        }
+       RecordIterator                  getRecordsEnd                           (void) const { return m_records.end();          }
+
+private:
+       typedef de::AppendList<AllocationCallbackRecord> Records;
+
+       Records                                 m_records;
+};
+
+//! Allocator that starts returning null after N allocs
+class DeterministicFailAllocator : public ChainedAllocator
+{
+public:
+                                                       DeterministicFailAllocator      (const VkAllocationCallbacks* allocator, deUint32 numPassingAllocs);
+                                                       ~DeterministicFailAllocator     (void);
+
+       void*                                   allocate                                        (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+       void*                                   reallocate                                      (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+
+private:
+       const deUint32                  m_numPassingAllocs;
+       volatile deUint32               m_allocationNdx;
+};
+
+struct AllocationCallbackViolation
+{
+       enum Reason
+       {
+               REASON_DOUBLE_FREE = 0,
+               REASON_FREE_NOT_ALLOCATED_PTR,
+               REASON_REALLOC_NOT_ALLOCATED_PTR,
+               REASON_REALLOC_FREED_PTR,
+               REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL,
+               REASON_INVALID_ALLOCATION_SCOPE,
+               REASON_INVALID_INTERNAL_ALLOCATION_TYPE,
+               REASON_INVALID_ALIGNMENT,
+               REASON_REALLOC_DIFFERENT_ALIGNMENT,
+
+               REASON_LAST
+       };
+
+       AllocationCallbackRecord        record;
+       Reason                                          reason;
+
+       AllocationCallbackViolation (void)
+               : reason(REASON_LAST)
+       {}
+
+       AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_)
+               : record(record_)
+               , reason(reason_)
+       {}
+};
+
+struct AllocationCallbackValidationResults
+{
+       std::vector<AllocationCallbackRecord>           liveAllocations;
+       size_t                                                                          internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST];
+       std::vector<AllocationCallbackViolation>        violations;
+
+                                                                                               AllocationCallbackValidationResults     (void);
+
+       void                                                                            clear                                                           (void);
+};
+
+void                                                   validateAllocationCallbacks     (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results);
+bool                                                   checkAndLog                                     (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits);
+bool                                                   validateAndLog                          (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits);
+
+std::ostream&                                  operator<<                                      (std::ostream& str, const AllocationCallbackRecord& record);
+std::ostream&                                  operator<<                                      (std::ostream& str, const AllocationCallbackViolation& violation);
+
+const VkAllocationCallbacks*   getSystemAllocator                      (void);
+
+} // vk
+
+#endif // _VKALLOCATIONCALLBACKUTIL_HPP
index 6ead17e..c98d50f 100644 (file)
@@ -233,7 +233,7 @@ void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst,
 
                        {
                                const deUint64  compileStartTime        = deGetMicroseconds();
-                               const int               compileRes                      = shader.parse(&builtinRes, 110, false, EShMsgSpvRules);
+                               const int               compileRes                      = shader.parse(&builtinRes, 110, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
                                glu::ShaderInfo shaderBuildInfo;
 
                                shaderBuildInfo.type                    = (glu::ShaderType)shaderType;
@@ -250,7 +250,7 @@ void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst,
 
                        {
                                const deUint64  linkStartTime   = deGetMicroseconds();
-                               const int               linkRes                 = program.link(EShMsgDefault);
+                               const int               linkRes                 = program.link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
 
                                buildInfo->program.infoLog              = program.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
                                buildInfo->program.linkOk               = (linkRes != 0);
index 7eb7a08..5dc290a 100644 (file)
@@ -817,7 +817,7 @@ tcu::Sampler::FilterMode mapVkMinTexFilter (VkFilter filter, VkSamplerMipmapMode
                case VK_FILTER_LINEAR:
                        switch (mipMode)
                        {
-                               case VK_SAMPLER_MIPMAP_MODE_BASE:               return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
+                               case VK_SAMPLER_MIPMAP_MODE_BASE:               return tcu::Sampler::LINEAR;
                                case VK_SAMPLER_MIPMAP_MODE_LINEAR:             return tcu::Sampler::LINEAR_MIPMAP_LINEAR;
                                case VK_SAMPLER_MIPMAP_MODE_NEAREST:    return tcu::Sampler::LINEAR_MIPMAP_NEAREST;
                                default:
@@ -828,7 +828,7 @@ tcu::Sampler::FilterMode mapVkMinTexFilter (VkFilter filter, VkSamplerMipmapMode
                case VK_FILTER_NEAREST:
                        switch (mipMode)
                        {
-                               case VK_SAMPLER_MIPMAP_MODE_BASE:               return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
+                               case VK_SAMPLER_MIPMAP_MODE_BASE:               return tcu::Sampler::NEAREST;
                                case VK_SAMPLER_MIPMAP_MODE_LINEAR:             return tcu::Sampler::NEAREST_MIPMAP_LINEAR;
                                case VK_SAMPLER_MIPMAP_MODE_NEAREST:    return tcu::Sampler::NEAREST_MIPMAP_NEAREST;
                                default:
@@ -889,4 +889,50 @@ tcu::UVec4 mapVkComponentMapping (const vk::VkComponentMapping& mapping)
        return swizzle;
 }
 
+//! Get a format the matches the layout in buffer memory used for a
+//! buffer<->image copy on a depth/stencil format.
+tcu::TextureFormat getDepthCopyFormat (VkFormat combinedFormat)
+{
+       switch (combinedFormat)
+       {
+               case VK_FORMAT_D16_UNORM:
+               case VK_FORMAT_X8_D24_UNORM_PACK32:
+               case VK_FORMAT_D32_SFLOAT:
+                       return mapVkFormat(combinedFormat);
+
+               case VK_FORMAT_D16_UNORM_S8_UINT:
+                       return mapVkFormat(VK_FORMAT_D16_UNORM);
+               case VK_FORMAT_D24_UNORM_S8_UINT:
+                       return mapVkFormat(VK_FORMAT_X8_D24_UNORM_PACK32);
+               case VK_FORMAT_D32_SFLOAT_S8_UINT:
+                       return mapVkFormat(VK_FORMAT_D32_SFLOAT);
+
+               case VK_FORMAT_S8_UINT:
+               default:
+                       DE_FATAL("Unexpected depth/stencil format");
+                       return tcu::TextureFormat();
+       }
+}
+
+//! Get a format the matches the layout in buffer memory used for a
+//! buffer<->image copy on a depth/stencil format.
+tcu::TextureFormat getStencilCopyFormat (VkFormat combinedFormat)
+{
+       switch (combinedFormat)
+       {
+               case VK_FORMAT_D16_UNORM_S8_UINT:
+               case VK_FORMAT_D24_UNORM_S8_UINT:
+               case VK_FORMAT_D32_SFLOAT_S8_UINT:
+               case VK_FORMAT_S8_UINT:
+                       return mapVkFormat(VK_FORMAT_S8_UINT);
+
+               case VK_FORMAT_D16_UNORM:
+               case VK_FORMAT_X8_D24_UNORM_PACK32:
+               case VK_FORMAT_D32_SFLOAT:
+               default:
+                       DE_FATAL("Unexpected depth/stencil format");
+                       return tcu::TextureFormat();
+       }
+}
+
 } // vk
index 6084945..c130b57 100644 (file)
@@ -53,6 +53,8 @@ bool                                          isCompressedFormat                      (VkFormat format);
 
 tcu::TextureFormat                     mapVkFormat                                     (VkFormat format);
 tcu::CompressedTexFormat       mapVkCompressedFormat           (VkFormat format);
+tcu::TextureFormat                     getDepthCopyFormat                      (VkFormat combinedFormat);
+tcu::TextureFormat                     getStencilCopyFormat            (VkFormat combinedFormat);
 
 tcu::Sampler                           mapVkSampler                            (const VkSamplerCreateInfo& samplerCreateInfo);
 tcu::Sampler::CompareMode      mapVkSamplerCompareOp           (VkCompareOp compareOp);
index 283f81d..b685974 100644 (file)
@@ -49,6 +49,101 @@ namespace
 
 using std::vector;
 
+// Memory management
+
+template<typename T>
+void* allocateSystemMem (const VkAllocationCallbacks* pAllocator, VkSystemAllocationScope scope)
+{
+       void* ptr = pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(T), sizeof(void*), scope);
+       if (!ptr)
+               throw std::bad_alloc();
+       return ptr;
+}
+
+void freeSystemMem (const VkAllocationCallbacks* pAllocator, void* mem)
+{
+       pAllocator->pfnFree(pAllocator->pUserData, mem);
+}
+
+template<typename Object, typename Handle, typename Parent, typename CreateInfo>
+Handle allocateHandle (Parent parent, const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+       Object* obj = DE_NULL;
+
+       if (pAllocator)
+       {
+               void* mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+               try
+               {
+                       obj = new (mem) Object(parent, pCreateInfo);
+                       DE_ASSERT(obj == mem);
+               }
+               catch (...)
+               {
+                       pAllocator->pfnFree(pAllocator->pUserData, mem);
+                       throw;
+               }
+       }
+       else
+               obj = new Object(parent, pCreateInfo);
+
+       return reinterpret_cast<Handle>(obj);
+}
+
+template<typename Object, typename Handle, typename CreateInfo>
+Handle allocateHandle (const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+       Object* obj = DE_NULL;
+
+       if (pAllocator)
+       {
+               void* mem = allocateSystemMem<Object>(pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+               try
+               {
+                       obj = new (mem) Object(pCreateInfo);
+                       DE_ASSERT(obj == mem);
+               }
+               catch (...)
+               {
+                       pAllocator->pfnFree(pAllocator->pUserData, mem);
+                       throw;
+               }
+       }
+       else
+               obj = new Object(pCreateInfo);
+
+       return reinterpret_cast<Handle>(obj);
+}
+
+template<typename Object, typename Handle>
+void freeHandle (Handle handle, const VkAllocationCallbacks* pAllocator)
+{
+       Object* obj = reinterpret_cast<Object*>(handle);
+
+       if (pAllocator)
+       {
+               obj->~Object();
+               freeSystemMem(pAllocator, reinterpret_cast<void*>(obj));
+       }
+       else
+               delete obj;
+}
+
+template<typename Object, typename Handle, typename CreateInfo>
+Handle allocateNonDispHandle (VkDevice device, const CreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator)
+{
+       Object* const   obj             = allocateHandle<Object, Object*>(device, pCreateInfo, pAllocator);
+       return Handle((deUint64)(deUintptr)obj);
+}
+
+template<typename Object, typename Handle>
+void freeNonDispHandle (Handle handle, const VkAllocationCallbacks* pAllocator)
+{
+       freeHandle<Object>(reinterpret_cast<Object*>((deUintptr)handle.getInternal()), pAllocator);
+}
+
+// Object definitions
+
 #define VK_NULL_RETURN(STMT)                                   \
        do {                                                                            \
                try {                                                                   \
@@ -271,6 +366,8 @@ void DescriptorPool::reset (void)
        m_managedSets.clear();
 }
 
+// API implementation
+
 extern "C"
 {
 
@@ -284,18 +381,56 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL getDeviceProcAddr (VkDevice device, con
        return reinterpret_cast<Device*>(device)->getProcAddr(pName);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL createGraphicsPipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks*, VkPipeline* pPipelines)
+VKAPI_ATTR VkResult VKAPI_CALL createGraphicsPipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines)
 {
-       for (deUint32 ndx = 0; ndx < count; ndx++)
-               pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
-       return VK_SUCCESS;
+       deUint32 allocNdx;
+       try
+       {
+               for (allocNdx = 0; allocNdx < count; allocNdx++)
+                       pPipelines[allocNdx] = allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos+allocNdx, pAllocator);
+
+               return VK_SUCCESS;
+       }
+       catch (const std::bad_alloc&)
+       {
+               for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+                       freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+               return VK_ERROR_OUT_OF_HOST_MEMORY;
+       }
+       catch (VkResult err)
+       {
+               for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+                       freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+               return err;
+       }
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL createComputePipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks*, VkPipeline* pPipelines)
+VKAPI_ATTR VkResult VKAPI_CALL createComputePipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines)
 {
-       for (deUint32 ndx = 0; ndx < count; ndx++)
-               pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
-       return VK_SUCCESS;
+       deUint32 allocNdx;
+       try
+       {
+               for (allocNdx = 0; allocNdx < count; allocNdx++)
+                       pPipelines[allocNdx] = allocateNonDispHandle<Pipeline, VkPipeline>(device, pCreateInfos+allocNdx, pAllocator);
+
+               return VK_SUCCESS;
+       }
+       catch (const std::bad_alloc&)
+       {
+               for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+                       freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+               return VK_ERROR_OUT_OF_HOST_MEMORY;
+       }
+       catch (VkResult err)
+       {
+               for (deUint32 freeNdx = 0; freeNdx < allocNdx; freeNdx++)
+                       freeNonDispHandle<Pipeline, VkPipeline>(pPipelines[freeNdx], pAllocator);
+
+               return err;
+       }
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL enumeratePhysicalDevices (VkInstance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pDevices)
index d3a627b..176b8a2 100644 (file)
 VKAPI_ATTR VkResult VKAPI_CALL createInstance (const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pInstance = reinterpret_cast<VkInstance>(new Instance(pCreateInfo)));
+       VK_NULL_RETURN((*pInstance = allocateHandle<Instance, VkInstance>(pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createDevice (VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pDevice = reinterpret_cast<VkDevice>(new Device(physicalDevice, pCreateInfo)));
+       VK_NULL_RETURN((*pDevice = allocateHandle<Device, VkDevice>(physicalDevice, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL allocateMemory (VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pMemory = VkDeviceMemory((deUint64)(deUintptr)new DeviceMemory(device, pAllocateInfo)));
+       VK_NULL_RETURN((*pMemory = allocateNonDispHandle<DeviceMemory, VkDeviceMemory>(device, pAllocateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createFence (VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pFence = VkFence((deUint64)(deUintptr)new Fence(device, pCreateInfo)));
+       VK_NULL_RETURN((*pFence = allocateNonDispHandle<Fence, VkFence>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createSemaphore (VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pSemaphore = VkSemaphore((deUint64)(deUintptr)new Semaphore(device, pCreateInfo)));
+       VK_NULL_RETURN((*pSemaphore = allocateNonDispHandle<Semaphore, VkSemaphore>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createEvent (VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pEvent = VkEvent((deUint64)(deUintptr)new Event(device, pCreateInfo)));
+       VK_NULL_RETURN((*pEvent = allocateNonDispHandle<Event, VkEvent>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createQueryPool (VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pQueryPool = VkQueryPool((deUint64)(deUintptr)new QueryPool(device, pCreateInfo)));
+       VK_NULL_RETURN((*pQueryPool = allocateNonDispHandle<QueryPool, VkQueryPool>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createBuffer (VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pBuffer = VkBuffer((deUint64)(deUintptr)new Buffer(device, pCreateInfo)));
+       VK_NULL_RETURN((*pBuffer = allocateNonDispHandle<Buffer, VkBuffer>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createBufferView (VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pView = VkBufferView((deUint64)(deUintptr)new BufferView(device, pCreateInfo)));
+       VK_NULL_RETURN((*pView = allocateNonDispHandle<BufferView, VkBufferView>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createImage (VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pImage = VkImage((deUint64)(deUintptr)new Image(device, pCreateInfo)));
+       VK_NULL_RETURN((*pImage = allocateNonDispHandle<Image, VkImage>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createImageView (VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pView = VkImageView((deUint64)(deUintptr)new ImageView(device, pCreateInfo)));
+       VK_NULL_RETURN((*pView = allocateNonDispHandle<ImageView, VkImageView>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createShaderModule (VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pShaderModule = VkShaderModule((deUint64)(deUintptr)new ShaderModule(device, pCreateInfo)));
+       VK_NULL_RETURN((*pShaderModule = allocateNonDispHandle<ShaderModule, VkShaderModule>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createPipelineCache (VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pPipelineCache = VkPipelineCache((deUint64)(deUintptr)new PipelineCache(device, pCreateInfo)));
+       VK_NULL_RETURN((*pPipelineCache = allocateNonDispHandle<PipelineCache, VkPipelineCache>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createPipelineLayout (VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pPipelineLayout = VkPipelineLayout((deUint64)(deUintptr)new PipelineLayout(device, pCreateInfo)));
+       VK_NULL_RETURN((*pPipelineLayout = allocateNonDispHandle<PipelineLayout, VkPipelineLayout>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createSampler (VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pSampler = VkSampler((deUint64)(deUintptr)new Sampler(device, pCreateInfo)));
+       VK_NULL_RETURN((*pSampler = allocateNonDispHandle<Sampler, VkSampler>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createDescriptorSetLayout (VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pSetLayout = VkDescriptorSetLayout((deUint64)(deUintptr)new DescriptorSetLayout(device, pCreateInfo)));
+       VK_NULL_RETURN((*pSetLayout = allocateNonDispHandle<DescriptorSetLayout, VkDescriptorSetLayout>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createDescriptorPool (VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pDescriptorPool = VkDescriptorPool((deUint64)(deUintptr)new DescriptorPool(device, pCreateInfo)));
+       VK_NULL_RETURN((*pDescriptorPool = allocateNonDispHandle<DescriptorPool, VkDescriptorPool>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createFramebuffer (VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pFramebuffer = VkFramebuffer((deUint64)(deUintptr)new Framebuffer(device, pCreateInfo)));
+       VK_NULL_RETURN((*pFramebuffer = allocateNonDispHandle<Framebuffer, VkFramebuffer>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createRenderPass (VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pRenderPass = VkRenderPass((deUint64)(deUintptr)new RenderPass(device, pCreateInfo)));
+       VK_NULL_RETURN((*pRenderPass = allocateNonDispHandle<RenderPass, VkRenderPass>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL createCommandPool (VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool)
 {
        DE_UNREF(pAllocator);
-       VK_NULL_RETURN(*pCommandPool = VkCommandPool((deUint64)(deUintptr)new CommandPool(device, pCreateInfo)));
+       VK_NULL_RETURN((*pCommandPool = allocateNonDispHandle<CommandPool, VkCommandPool>(device, pCreateInfo, pAllocator)));
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyInstance (VkInstance instance, const VkAllocationCallbacks* pAllocator)
 {
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Instance*>(instance);
+       freeHandle<Instance, VkInstance>(instance, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyDevice (VkDevice device, const VkAllocationCallbacks* pAllocator)
 {
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Device*>(device);
+       freeHandle<Device, VkDevice>(device, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL freeMemory (VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<DeviceMemory*>((deUintptr)memory.getInternal());
+       freeNonDispHandle<DeviceMemory, VkDeviceMemory>(memory, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyFence (VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Fence*>((deUintptr)fence.getInternal());
+       freeNonDispHandle<Fence, VkFence>(fence, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroySemaphore (VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Semaphore*>((deUintptr)semaphore.getInternal());
+       freeNonDispHandle<Semaphore, VkSemaphore>(semaphore, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyEvent (VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Event*>((deUintptr)event.getInternal());
+       freeNonDispHandle<Event, VkEvent>(event, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyQueryPool (VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<QueryPool*>((deUintptr)queryPool.getInternal());
+       freeNonDispHandle<QueryPool, VkQueryPool>(queryPool, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyBuffer (VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Buffer*>((deUintptr)buffer.getInternal());
+       freeNonDispHandle<Buffer, VkBuffer>(buffer, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyBufferView (VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<BufferView*>((deUintptr)bufferView.getInternal());
+       freeNonDispHandle<BufferView, VkBufferView>(bufferView, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyImage (VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Image*>((deUintptr)image.getInternal());
+       freeNonDispHandle<Image, VkImage>(image, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyImageView (VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<ImageView*>((deUintptr)imageView.getInternal());
+       freeNonDispHandle<ImageView, VkImageView>(imageView, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyShaderModule (VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<ShaderModule*>((deUintptr)shaderModule.getInternal());
+       freeNonDispHandle<ShaderModule, VkShaderModule>(shaderModule, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyPipelineCache (VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<PipelineCache*>((deUintptr)pipelineCache.getInternal());
+       freeNonDispHandle<PipelineCache, VkPipelineCache>(pipelineCache, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyPipeline (VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Pipeline*>((deUintptr)pipeline.getInternal());
+       freeNonDispHandle<Pipeline, VkPipeline>(pipeline, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyPipelineLayout (VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<PipelineLayout*>((deUintptr)pipelineLayout.getInternal());
+       freeNonDispHandle<PipelineLayout, VkPipelineLayout>(pipelineLayout, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroySampler (VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Sampler*>((deUintptr)sampler.getInternal());
+       freeNonDispHandle<Sampler, VkSampler>(sampler, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyDescriptorSetLayout (VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<DescriptorSetLayout*>((deUintptr)descriptorSetLayout.getInternal());
+       freeNonDispHandle<DescriptorSetLayout, VkDescriptorSetLayout>(descriptorSetLayout, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<DescriptorPool*>((deUintptr)descriptorPool.getInternal());
+       freeNonDispHandle<DescriptorPool, VkDescriptorPool>(descriptorPool, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyFramebuffer (VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<Framebuffer*>((deUintptr)framebuffer.getInternal());
+       freeNonDispHandle<Framebuffer, VkFramebuffer>(framebuffer, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyRenderPass (VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<RenderPass*>((deUintptr)renderPass.getInternal());
+       freeNonDispHandle<RenderPass, VkRenderPass>(renderPass, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL destroyCommandPool (VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator)
 {
        DE_UNREF(device);
-       DE_UNREF(pAllocator);
-       delete reinterpret_cast<CommandPool*>((deUintptr)commandPool.getInternal());
+       freeNonDispHandle<CommandPool, VkCommandPool>(commandPool, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL getPhysicalDeviceFeatures (VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures)
index 2b0ae6f..928be2a 100644 (file)
@@ -35,6 +35,7 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vkDefs.hpp"
+#include "deMemory.h"
 
 #include <vector>
 
@@ -56,6 +57,25 @@ std::vector<VkExtensionProperties>           enumerateDeviceExtensionProperties              (const I
 
 bool                                                                   isShaderStageSupported                                  (const VkPhysicalDeviceFeatures& deviceFeatures, VkShaderStageFlagBits stage);
 
+template <typename Context, typename Interface, typename Type>
+bool validateInitComplete(Context context, void (Interface::*Function)(Context, Type*)const, const Interface& interface)
+{
+       Type vec[2];
+       deMemset(&vec[0], 0x00, sizeof(Type));
+       deMemset(&vec[1], 0xFF, sizeof(Type));
+
+       (interface.*Function)(context, &vec[0]);
+       (interface.*Function)(context, &vec[1]);
+
+       for (size_t ndx = 0; ndx < sizeof(Type); ndx++)
+       {
+               if (reinterpret_cast<deUint8*>(&vec[0])[ndx] != reinterpret_cast<deUint8*>(&vec[1])[ndx])
+                       return false;
+       }
+
+       return true;
+}
+
 } // vk
 
 #endif // _VKQUERYUTIL_HPP
index e889007..17cafe3 100644 (file)
@@ -674,16 +674,16 @@ def writeNullDriverImpl (api, filename):
 
                for function in createFuncs:
                        objectType      = function.arguments[-1].type.replace("*", "").strip()
-                       argsStr         = ", ".join([a.name for a in function.arguments[:-2]])
+                       argsStr         = ", ".join([a.name for a in function.arguments[:-1]])
 
                        yield "VKAPI_ATTR %s VKAPI_CALL %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
                        yield "{"
                        yield "\tDE_UNREF(%s);" % function.arguments[-2].name
 
                        if getHandle(objectType).type == Handle.TYPE_NONDISP:
-                               yield "\tVK_NULL_RETURN(*%s = %s((deUint64)(deUintptr)new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+                               yield "\tVK_NULL_RETURN((*%s = allocateNonDispHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
                        else:
-                               yield "\tVK_NULL_RETURN(*%s = reinterpret_cast<%s>(new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+                               yield "\tVK_NULL_RETURN((*%s = allocateHandle<%s, %s>(%s)));" % (function.arguments[-1].name, objectType[2:], objectType, argsStr)
 
                        yield "}"
                        yield ""
@@ -695,12 +695,11 @@ def writeNullDriverImpl (api, filename):
                        yield "{"
                        for arg in function.arguments[:-2]:
                                yield "\tDE_UNREF(%s);" % arg.name
-                       yield "\tDE_UNREF(%s);" % function.arguments[-1].name
 
                        if getHandle(objectArg.type).type == Handle.TYPE_NONDISP:
-                               yield "\tdelete reinterpret_cast<%s*>((deUintptr)%s.getInternal());" % (objectArg.type[2:], objectArg.name)
+                               yield "\tfreeNonDispHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
                        else:
-                               yield "\tdelete reinterpret_cast<%s*>(%s);" % (objectArg.type[2:], objectArg.name)
+                               yield "\tfreeHandle<%s, %s>(%s, %s);" % (objectArg.type[2:], objectArg.type, objectArg.name, function.arguments[-1].name)
 
                        yield "}"
                        yield ""
index 8d75651..88e1c18 100644 (file)
@@ -27,8 +27,6 @@ set(DEQP_VK_COMMON_SRCS
        vktTestCaseUtil.hpp
        vktTestPackage.cpp
        vktTestPackage.hpp
-       vktInfo.cpp
-       vktInfo.hpp
        vktShaderLibrary.cpp
        vktShaderLibrary.hpp
        vktRenderPassTests.cpp
index 93dcca0..fc48238 100644 (file)
@@ -17,6 +17,8 @@ set(DEQP_VK_API_SRCS
        vktApiBufferViewCreateTests.hpp
        vktApiBufferViewAccessTests.cpp
        vktApiBufferViewAccessTests.hpp
+       vktApiFeatureInfo.cpp
+       vktApiFeatureInfo.hpp
        )
 
 set(DEQP_VK_API_LIBS
index c88d1d4..0cce45e 100644 (file)
@@ -160,7 +160,7 @@ tcu::TestStatus BufferTestInstance::iterate (void)
 {
        const VkDeviceSize testSizes[] =
        {
-               0,
+               1,
                1181,
                15991,
                16384
index 7bff391..aa87868 100644 (file)
@@ -66,7 +66,6 @@ struct BufferViewCaseParams
        deUint32        bufferSize;
        deUint32        bufferViewSize;
        deUint32        elementOffset;
-       deUint32        offset;
 };
 
 class BufferViewTestInstance : public vkt::TestInstance
@@ -122,10 +121,10 @@ private:
        Move<VkFence>                                           m_fence;
 };
 
-static void generateBuffer (std::vector<tcu::IVec4>& uniformData, deUint32 bufferSize, deInt8 factor = 1)
+static void generateBuffer (std::vector<deUint32>& uniformData, deUint32 bufferSize, deInt8 factor = 1)
 {
        for (deUint32 i = 0; i < bufferSize; ++i)
-               uniformData.push_back(tcu::IVec4(factor * i, factor * (i + 1), factor * (i + 2), factor * (i + 3)));
+               uniformData.push_back(factor * i);
 }
 
 void BufferViewTestInstance::createQuad (void)
@@ -308,7 +307,7 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                {
                        {
                                0u,                                                                                     // deUint32                             binding;
-                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,                      // VkDescriptorType             descriptorType;
+                               VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,        // VkDescriptorType             descriptorType;
                                1u,                                                                                     // deUint32                             arraySize;
                                VK_SHADER_STAGE_ALL,                                            // VkShaderStageFlags   stageFlags;
                                DE_NULL                                                                         // const VkSampler*             pImmutableSamplers;
@@ -327,10 +326,10 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams);
 
                // Generate buffer
-               std::vector<tcu::IVec4> uniformData;
+               std::vector<deUint32> uniformData;
                generateBuffer(uniformData, testCase.bufferSize);
 
-               const VkDeviceSize uniformSize = testCase.bufferSize * sizeof(tcu::Vec4);
+               const VkDeviceSize uniformSize = testCase.bufferSize * sizeof(deUint32);
                const VkBufferCreateInfo uniformBufferParams =
                {
                        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
@@ -356,8 +355,8 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                        (VkBufferViewCreateFlags)0,
                        *m_uniformBuffer,                                                                                                       // VkBuffer                     buffer;
                        m_colorFormat,                                                                                                          // VkFormat                     format;
-                       m_testCase.elementOffset * sizeof(tcu::IVec4) + m_testCase.offset,      // VkDeviceSize         offset;
-                       m_testCase.bufferViewSize * sizeof(tcu::IVec4)                                          // VkDeviceSize         range;
+                       m_testCase.elementOffset * sizeof(deUint32),                                            // VkDeviceSize         offset;
+                       m_testCase.bufferViewSize * sizeof(deUint32)                                            // VkDeviceSize         range;
                };
 
                m_uniformBufferView = createBufferView(vk, vkDevice, &viewInfo);
@@ -365,7 +364,7 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                const VkDescriptorPoolSize descriptorTypes[1] =
                {
                        {
-                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,                              // VkDescriptorType             type;
+                               VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,                // VkDescriptorType             type;
                                1                                                                                               // deUint32                             count;
                        }
                };
@@ -537,6 +536,19 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                        1.0f,                                                                                                                   // float                        lineWidth;
                };
 
+               const VkPipelineMultisampleStateCreateInfo              multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                                   // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
+                       VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
+               };
+
                const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
                {
                        false,                                                                                                          // VkBool32                     blendEnable;
@@ -585,7 +597,7 @@ BufferViewTestInstance::BufferViewTestInstance (Context& context, BufferViewCase
                        DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
                        &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
                        &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
-                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
                        DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
                        &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
                        &dynamicStateParams,                                                            // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
@@ -773,7 +785,7 @@ tcu::TestStatus BufferViewTestInstance::checkResult (deInt8 factor)
        for (deInt32 i = 0; i < (deInt32) m_renderSize.x(); ++i)
        {
                tcu::IVec4 pixel        = pixelBuffer.getPixelInt(i, i);
-               deInt32 expected        = factor * (m_testCase.elementOffset + i + (m_testCase.offset / 4) % 4);
+               deInt32 expected        = factor * (m_testCase.elementOffset + i);
                deInt32 actual          = pixel[0];
                if (expected != actual)
                {
@@ -814,8 +826,8 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
        }
 
        // Generate and bind another buffer
-       std::vector<tcu::IVec4>         uniformData;
-       const VkDeviceSize                      uniformSize     = m_testCase.bufferSize * sizeof(tcu::Vec4);
+       std::vector<deUint32>           uniformData;
+       const VkDeviceSize                      uniformSize = m_testCase.bufferSize * sizeof(deUint32);
        const deInt8                            factor          = 2;
 
        generateBuffer(uniformData, m_testCase.bufferSize, factor);
@@ -863,13 +875,12 @@ void BufferViewTestCase::initPrograms (SourceCollections& programCollection) con
 
        programCollection.glslSources.add("frag") << glu::FragmentSource(
                "#version 310 es\n"
-               "layout (set=0, binding=0) uniform u_buffer {\n"
-               "       highp uint item[" + de::toString(m_bufferViewTestInfo.bufferViewSize) + "];\n"
-               "};\n"
+               "#extension GL_EXT_texture_buffer : enable\n"
+               "layout (set=0, binding=0) uniform highp usamplerBuffer u_buffer;\n"
                "layout (location = 0) out highp uint o_color;\n"
                "void main()\n"
                "{\n"
-               "       o_color = item[int(gl_FragCoord.x)];\n"
+               "       o_color = texelFetch(u_buffer, int(gl_FragCoord.x)).x;\n"
                "}\n");
 }
 
@@ -885,10 +896,9 @@ tcu::TestCaseGroup* createBufferViewAccessTests (tcu::TestContext& testCtx)
                        512,    // deUint32     bufferSize
                        512,    // deUint32     bufferViewSize
                        0,              // deUint32     elementOffset
-                       0,              // deUint32 offset
                };
                std::ostringstream description;
-               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
                bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_complete", description.str(), info));
        }
 
@@ -898,10 +908,9 @@ tcu::TestCaseGroup* createBufferViewAccessTests (tcu::TestContext& testCtx)
                        4096,   // deUint32     bufferSize
                        512,    // deUint32     bufferViewSize
                        0,              // deUint32     elementOffset
-                       0,              // deUint32 offset
                };
                std::ostringstream description;
-               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
                bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset0", description.str(), info));
        }
 
@@ -911,26 +920,12 @@ tcu::TestCaseGroup* createBufferViewAccessTests (tcu::TestContext& testCtx)
                        4096,   // deUint32     bufferSize
                        512,    // deUint32     bufferViewSize
                        128,    // deUint32     elementOffset
-                       0,              // deUint32 offset
                };
                std::ostringstream description;
-               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
+               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << info.bufferViewSize << " bufferView element offset: " << info.elementOffset;
                bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset1", description.str(), info));
        }
 
-       {
-               BufferViewCaseParams info =
-               {
-                       4096,   // deUint32     bufferSize
-                       512,    // deUint32     bufferViewSize
-                       128,    // deUint32     elementOffset
-                       4,              // deUint32 offset
-               };
-               std::ostringstream description;
-               description << "bufferSize: " << info.bufferSize << " bufferViewSize: " << " bufferView element offset: " << info.elementOffset << " offset: " << info.offset;
-               bufferViewTests->addChild(new BufferViewTestCase(testCtx, "buffer_view_memory_test_partial_offset2", description.str(), info));
-       }
-
        return bufferViewTests.release();
 }
 
index a33159e..dc1b016 100644 (file)
@@ -54,21 +54,19 @@ namespace
 
 struct BufferViewCaseParameters
 {
-       VkFormat                        format;
-       VkDeviceSize            offset;
-       VkDeviceSize            range;
-       VkBufferUsageFlags      usage;
-       bool                            beforeAllocateMemory;
+       VkFormat                                format;
+       VkDeviceSize                    offset;
+       VkDeviceSize                    range;
+       VkBufferUsageFlags              usage;
+       VkFormatFeatureFlags    features;
+       bool                                    beforeAllocateMemory;
 };
 
 class BufferViewTestInstance : public TestInstance
 {
 public:
                                                                BufferViewTestInstance          (Context&                                       ctx,
-                                                                                                                        BufferViewCaseParameters       createInfo)
-                                                                       : TestInstance                  (ctx)
-                                                                       , m_testCase                    (createInfo)
-                                                               {}
+                                                                                                                        BufferViewCaseParameters       createInfo);
        virtual tcu::TestStatus         iterate                                         (void);
 
 private:
@@ -96,6 +94,15 @@ private:
        BufferViewCaseParameters        m_testCase;
 };
 
+BufferViewTestInstance::BufferViewTestInstance (Context&                                       ctx,
+                                                                                               BufferViewCaseParameters        createInfo)
+       : TestInstance  (ctx)
+       , m_testCase    (createInfo)
+{
+       if (m_context.getDeviceFeatures().sparseBinding == 0 && m_testCase.beforeAllocateMemory == false)
+               throw tcu::NotSupportedError("The test is not supported - it needs missing 'sparseBinding' feature of Vulkan");
+}
+
 tcu::TestStatus BufferViewTestInstance::iterate (void)
 {
        // Create buffer
@@ -108,18 +115,20 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
        VkFormatProperties                      properties;
        const VkBufferCreateInfo        bufferParams =
        {
-               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //      VkStructureType                 sType;
-               DE_NULL,                                                                        //      const void*                             pNext;
-               VK_BUFFER_CREATE_SPARSE_BINDING_BIT,            //      VkBufferCreateFlags             flags;
-               size,                                                                           //      VkDeviceSize                    size;
-               m_testCase.usage,                                                       //      VkBufferUsageFlags              usage;
-               VK_SHARING_MODE_EXCLUSIVE,                                      //      VkSharingMode                   sharingMode;
-               1u,                                                                                     //      deUint32                                queueFamilyCount;
-               &queueFamilyIndex,                                                      //      const deUint32*                 pQueueFamilyIndices;
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                                                                                   //      VkStructureType                 sType;
+               DE_NULL,                                                                                                                                                                //      const void*                             pNext;
+               (VkBufferCreateFlags)(m_testCase.beforeAllocateMemory == true
+                                                         ? 0
+                                                         : VK_BUFFER_CREATE_SPARSE_BINDING_BIT),                                                       //      VkBufferCreateFlags             flags;
+               size,                                                                                                                                                                   //      VkDeviceSize                    size;
+               m_testCase.usage,                                                                                                                                               //      VkBufferUsageFlags              usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                                                                                                              //      VkSharingMode                   sharingMode;
+               1u,                                                                                                                                                                             //      deUint32                                queueFamilyCount;
+               &queueFamilyIndex,                                                                                                                                              //      const deUint32*                 pQueueFamilyIndices;
        };
 
        m_context.getInstanceInterface().getPhysicalDeviceFormatProperties(m_context.getPhysicalDevice(), m_testCase.format, &properties);
-       if (!(properties.bufferFeatures & m_testCase.usage))
+       if (!(properties.bufferFeatures & m_testCase.features))
                TCU_THROW(NotSupportedError, "Format not supported");
 
        if (vk.createBuffer(vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL, &testBuffer) != VK_SUCCESS)
@@ -229,6 +238,7 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
                                0,                                                                                      // VkDeviceSize                 offset;
                                range,                                                                          // VkDeviceSize                 range;
                                VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,       // VkBufferUsageFlags   usage;
+                               VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
                                false                                                                           // beforeAlloceMemory   bool;
                        };
                        bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_before_uniform", testDescription.str(), testParams));
@@ -240,6 +250,7 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
                                0,                                                                                      // VkDeviceSize                 offset;
                                range,                                                                          // VkDeviceSize                 range;
                                VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,       // VkBufferUsageFlags   usage;
+                               VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
                                true                                                                            // beforeAlloceMemory   bool;
                        };
                        bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_after_uniform", testDescription.str(), testParams));
@@ -251,6 +262,7 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
                                0,                                                                                      // VkDeviceSize                 offset;
                                range,                                                                          // VkDeviceSize                 range;
                                VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,       // VkBufferUsageFlags   usage;
+                               VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
                                false                                                                           // beforeAlloceMemory   bool;
                        };
                        bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_before_storage", testDescription.str(), testParams));
@@ -262,6 +274,7 @@ tcu::TestStatus BufferViewTestInstance::iterate (void)
                                0,                                                                                      // VkDeviceSize                 offset;
                                range,                                                                          // VkDeviceSize                 range;
                                VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,       // VkBufferUsageFlags   usage;
+                               VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, // VkFormatFeatureFlags flags;
                                true                                                                            // beforeAlloceMemory   bool;
                        };
                        bufferViewTests->addChild(new BufferViewTestCase(testCtx, testName.str() + "_after_storage", testDescription.str(), testParams));
index 8a476d8..0421ff6 100644 (file)
@@ -489,6 +489,18 @@ tcu::TestStatus createDeviceWithUnsupportedExtensionsTest (Context& context)
        }
 }
 
+deUint32 getGlobalMaxQueueCount(const vector<VkQueueFamilyProperties>& queueFamilyProperties)
+{
+       deUint32 maxQueueCount = 0;
+
+       for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < (deUint32)queueFamilyProperties.size(); queueFamilyNdx++)
+       {
+               maxQueueCount = de::max(maxQueueCount, queueFamilyProperties[queueFamilyNdx].queueCount);
+       }
+
+       return maxQueueCount;
+}
+
 tcu::TestStatus createDeviceWithVariousQueueCountsTest (Context& context)
 {
        tcu::TestLog&                                                   log                                             = context.getTestContext().getLog();
@@ -498,6 +510,7 @@ tcu::TestStatus createDeviceWithVariousQueueCountsTest (Context& context)
        const InstanceDriver                                    instanceDriver                  (platformInterface, instance.get());
        const VkPhysicalDevice                                  physicalDevice                  = chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
        const vector<VkQueueFamilyProperties>   queueFamilyProperties   = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
+       const vector<float>                                             queuePriorities                 (getGlobalMaxQueueCount(queueFamilyProperties), 1.0f);
        vector<VkDeviceQueueCreateInfo>                 deviceQueueCreateInfos;
 
        for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < (deUint32)queueFamilyProperties.size(); queueFamilyNdx++)
@@ -513,7 +526,7 @@ tcu::TestStatus createDeviceWithVariousQueueCountsTest (Context& context)
                                (VkDeviceQueueCreateFlags)0u,
                                queueFamilyNdx,
                                queueCount,
-                               DE_NULL
+                               queuePriorities.data()
                        };
 
                        deviceQueueCreateInfos.push_back(queueCreateInfo);
diff --git a/external/vulkancts/modules/vulkan/api/vktApiFeatureInfo.cpp b/external/vulkancts/modules/vulkan/api/vktApiFeatureInfo.cpp
new file mode 100644 (file)
index 0000000..74735bf
--- /dev/null
@@ -0,0 +1,541 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * 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 Api Feature Query tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiFeatureInfo.hpp"
+
+#include "vktTestCaseUtil.hpp"
+
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deMemory.h"
+
+namespace vkt
+{
+namespace api
+{
+namespace
+{
+
+using namespace vk;
+using std::vector;
+using std::string;
+using tcu::TestLog;
+using tcu::ScopedLogSection;
+
+enum
+{
+       GUARD_SIZE      = 0x20,                 //!< Number of bytes to check
+       GUARD_VALUE     = 0xcd,                 //!< Data pattern
+};
+
+enum LimitFormat
+{
+       LIMIT_FORMAT_SIGNED_INT,
+       LIMIT_FORMAT_UNSIGNED_INT,
+       LIMIT_FORMAT_FLOAT,
+       LIMIT_FORMAT_DEVICE_SIZE,
+
+       LIMIT_FORMAT_LAST
+};
+
+enum LimitType
+{
+       LIMIT_TYPE_MIN,
+       LIMIT_TYPE_MAX,
+
+       LIMIT_TYPE_LAST
+};
+
+#define FEATURE(_X_)   DE_OFFSET_OF(VkPhysicalDeviceLimits, _X_),(char*)(#_X_)
+bool validateFeatureLimits(VkPhysicalDeviceProperties* properties, TestLog& log)
+{
+       bool                                    limitsOk        = true;
+       VkPhysicalDeviceLimits* limits          = &properties->limits;
+       struct FeatureLimitTable
+       {
+               deUint32                offset;
+               char*                   name;
+               deUint32                uintVal;                        //!< Format is UNSIGNED_INT
+               deInt32                 intVal;                         //!< Format is SIGNED_INT
+               deUint64                deviceSizeVal;          //!< Format is DEVICE_SIZE
+               float                   floatVal;                       //!< Format is FLOAT
+               LimitFormat             format;
+               LimitType               type;
+       } featureLimitTable[] =   //!< From gitlab.khronos.org/vulkan/vulkan.git:doc/specs/vulkan/chapters/features.txt@40de2de5b8167ec277ea2969d621857094323831
+       {
+               { FEATURE(maxImageDimension1D),                                                                 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxImageDimension2D),                                                                 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxImageDimension3D),                                                                 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxImageDimensionCube),                                                               4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxImageArrayLayers),                                                                 256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN    },
+               { FEATURE(maxTexelBufferElements),                                                              65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxUniformBufferRange),                                                               16384, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxPushConstantsSize),                                                                128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxMemoryAllocationCount),                                                    4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(bufferImageGranularity),                                                              0, 0, 131072, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MAX },
+               { FEATURE(sparseAddressSpaceSize),                                                              0, 0, 2UL*1024*1024*1024, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MIN },
+               { FEATURE(maxBoundDescriptorSets),                                                              4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxPerStageDescriptorSamplers),                                               16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxPerStageDescriptorUniformBuffers),                                 12, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxPerStageDescriptorStorageBuffers),                                 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxPerStageDescriptorSampledImages),                                  16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxPerStageDescriptorStorageImages),                                  4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxPerStageDescriptorInputAttachments),                               4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxDescriptorSetSamplers),                                                    96, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxDescriptorSetUniformBuffers),                                              72, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxDescriptorSetUniformBuffersDynamic),                               8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxDescriptorSetStorageBuffers),                                              24, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxDescriptorSetStorageBuffersDynamic),                               4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxDescriptorSetSampledImages),                                               96, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxDescriptorSetStorageImages),                                               24, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxVertexInputAttributes),                                                    16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxVertexInputBindings),                                                              16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxVertexInputAttributeOffset),                                               2047, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxVertexInputBindingStride),                                                 2048, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxVertexOutputComponents),                                                   64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationGenerationLevel),                                              64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationPatchSize),                                                    32, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxTessellationControlPerVertexInputComponents),              64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationControlPerVertexOutputComponents),             64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationControlPerPatchOutputComponents),              120, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationControlTotalOutputComponents),                 2048, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationEvaluationInputComponents),                    64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxTessellationEvaluationOutputComponents),                   64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxGeometryShaderInvocations),                                                32, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxGeometryInputComponents),                                                  64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxGeometryOutputComponents),                                                 64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxGeometryOutputVertices),                                                   256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxGeometryTotalOutputComponents),                                    1024, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxFragmentInputComponents),                                                  64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxFragmentOutputAttachments),                                                4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxFragmentDualSrcAttachments),                                               1, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxFragmentCombinedOutputResources),                                  4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN   },
+               { FEATURE(maxComputeSharedMemorySize),                                                  16384, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN    },
+               { FEATURE(maxComputeWorkGroupCount[0]),                                                 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN    },
+               { FEATURE(maxComputeWorkGroupCount[1]),                                                 65536, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN    },
+               { FEATURE(maxComputeWorkGroupCount[2]),                                                 65536,  0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN    },
+               { FEATURE(maxComputeWorkGroupInvocations),                                              128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(maxComputeWorkGroupSize[0]),                                                  128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(maxComputeWorkGroupSize[1]),                                                  128, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(maxComputeWorkGroupSize[2]),                                                  64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(subPixelPrecisionBits),                                                               4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(subTexelPrecisionBits),                                                               4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(mipmapPrecisionBits),                                                                 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(maxDrawIndirectCount),                                                                65535, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN     },
+               { FEATURE(maxSamplerLodBias),                                                                   0, 0, 0, 2.0f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(maxSamplerAnisotropy),                                                                0, 0, 0, 16.0f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(maxViewports),                                                                                16, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxViewportDimensions[0]),                                                    4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(maxViewportDimensions[1]),                                                    4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN  },
+               { FEATURE(viewportBoundsRange[0]),                                                              0, 0, 0, -8192, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(viewportBoundsRange[1]),                                                              0, 0, 0, 8191, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(viewportSubPixelBits),                                                                0, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(minMemoryMapAlignment),                                                               64, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(minTexelBufferOffsetAlignment),                                               256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+               { FEATURE(minUniformBufferOffsetAlignment),                                             256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+               { FEATURE(minStorageBufferOffsetAlignment),                                             256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MAX },
+               { FEATURE(minTexelOffset),                                                                              0, -8, 0, 0, LIMIT_FORMAT_SIGNED_INT, LIMIT_TYPE_MAX },
+               { FEATURE(maxTexelOffset),                                                                              7, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(minTexelGatherOffset),                                                                0, -8, 0, 0, LIMIT_FORMAT_SIGNED_INT, LIMIT_TYPE_MAX },
+               { FEATURE(maxTexelGatherOffset),                                                                7, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(minInterpolationOffset),                                                              0, 0, 0, -0.5f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(maxInterpolationOffset),                                                              0, 0, 0, 0.5f, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(subPixelInterpolationOffsetBits),                                             4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxFramebufferWidth),                                                                 4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxFramebufferHeight),                                                                4096, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxFramebufferLayers),                                                                256, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxColorAttachments),                                                                 4, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxSampleMaskWords),                                                                  1, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxClipDistances),                                                                    8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxCullDistances),                                                                    8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(maxCombinedClipAndCullDistances),                                             8, 0, 0, 0, LIMIT_FORMAT_UNSIGNED_INT, LIMIT_TYPE_MIN },
+               { FEATURE(pointSizeRange[0]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(pointSizeRange[1]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(pointSizeRange[0]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(pointSizeRange[1]),                                                                   0, 0, 0, 64.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(lineWidthRange[0]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(lineWidthRange[1]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(lineWidthRange[0]),                                                                   0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(lineWidthRange[1]),                                                                   0, 0, 0, 8.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MIN },
+               { FEATURE(pointSizeGranularity),                                                                0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(lineWidthGranularity),                                                                0, 0, 0, 1.0, LIMIT_FORMAT_FLOAT, LIMIT_TYPE_MAX },
+               { FEATURE(nonCoherentAtomSize),                                                                 0, 0, 128, 0, LIMIT_FORMAT_DEVICE_SIZE, LIMIT_TYPE_MAX },
+       };
+
+       log << TestLog::Message << *limits << TestLog::EndMessage;
+
+       for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(featureLimitTable); ndx++)
+       {
+               switch (featureLimitTable[ndx].format)
+               {
+                       case LIMIT_FORMAT_UNSIGNED_INT:
+                               if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+                               {
+                                       if (*((deUint32*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].uintVal)
+                                       {
+                                               log << TestLog::Message << "limit Validation failed " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MIN - actual is "
+                                                       << *((deUint32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (*((deUint32*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].uintVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed,  " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MAX - actual is "
+                                                       << *((deUint32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               break;
+
+                       case LIMIT_FORMAT_FLOAT:
+                               if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+                               {
+                                       if (*((float*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].floatVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MIN - actual is "
+                                                       << *((float*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (*((float*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].floatVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MAX actual is "
+                                                       << *((float*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               break;
+
+                       case LIMIT_FORMAT_SIGNED_INT:
+                               if (featureLimitTable[ndx].type == LIMIT_TYPE_MIN)
+                               {
+                                       if (*((deInt32*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].intVal)
+                                       {
+                                               log << TestLog::Message <<  "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MIN actual is "
+                                                       << *((deInt32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (*((deInt32*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].intVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MAX actual is "
+                                                       << *((deInt32*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               break;
+
+                       case LIMIT_FORMAT_DEVICE_SIZE:
+                               if ( featureLimitTable[ndx].type == LIMIT_TYPE_MIN )
+                               {
+                                       if (*((deUint64*)((char*)limits+featureLimitTable[ndx].offset)) < featureLimitTable[ndx].deviceSizeVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MIN actual is "
+                                                       << *((deUint64*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (*((deUint64*)((char*)limits+featureLimitTable[ndx].offset)) > featureLimitTable[ndx].deviceSizeVal)
+                                       {
+                                               log << TestLog::Message << "limit validation failed, " << featureLimitTable[ndx].name
+                                                       << " not valid-limit type MAX actual is "
+                                                       << *((deUint64*)((char*)limits + featureLimitTable[ndx].offset)) << TestLog::EndMessage;
+                                               limitsOk = false;
+                                       }
+                               }
+                               break;
+
+                       default:
+                               DE_ASSERT(0);
+                               limitsOk = false;
+               }
+       }
+
+       return limitsOk;
+}
+
+tcu::TestStatus enumeratePhysicalDevices (Context& context)
+{
+       TestLog&                                                log             = context.getTestContext().getLog();
+       const vector<VkPhysicalDevice>  devices = enumeratePhysicalDevices(context.getInstanceInterface(), context.getInstance());
+
+       log << TestLog::Integer("NumDevices", "Number of devices", "", QP_KEY_TAG_NONE, deInt64(devices.size()));
+
+       for (size_t ndx = 0; ndx < devices.size(); ndx++)
+               log << TestLog::Message << ndx << ": " << devices[ndx] << TestLog::EndMessage;
+
+       return tcu::TestStatus::pass("Enumerating devices succeeded");
+}
+
+tcu::TestStatus enumerateInstanceLayers (Context& context)
+{
+       TestLog&                                                log                     = context.getTestContext().getLog();
+       const vector<VkLayerProperties> properties      = enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+       for (size_t ndx = 0; ndx < properties.size(); ndx++)
+               log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+       return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateInstanceExtensions (Context& context)
+{
+       TestLog&        log             = context.getTestContext().getLog();
+
+       {
+               const ScopedLogSection                          section         (log, "Global", "Global Extensions");
+               const vector<VkExtensionProperties>     properties      = enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL);
+
+               for (size_t ndx = 0; ndx < properties.size(); ndx++)
+                       log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+       }
+
+       {
+               const vector<VkLayerProperties> layers  = enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+               for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+               {
+                       const ScopedLogSection                          section         (log, layer->layerName, string("Layer: ") + layer->layerName);
+                       const vector<VkExtensionProperties>     properties      = enumerateInstanceExtensionProperties(context.getPlatformInterface(), layer->layerName);
+
+                       for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+                               log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+               }
+       }
+
+       return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus enumerateDeviceLayers (Context& context)
+{
+       TestLog&                                                log                     = context.getTestContext().getLog();
+       const vector<VkLayerProperties> properties      = vk::enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+       for (size_t ndx = 0; ndx < properties.size(); ndx++)
+               log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+       return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateDeviceExtensions (Context& context)
+{
+       TestLog&        log             = context.getTestContext().getLog();
+
+       {
+               const ScopedLogSection                          section         (log, "Global", "Global Extensions");
+               const vector<VkExtensionProperties>     properties      = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), DE_NULL);
+
+               for (size_t ndx = 0; ndx < properties.size(); ndx++)
+                       log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+       }
+
+       {
+               const vector<VkLayerProperties> layers  = enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+               for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+               {
+                       const ScopedLogSection                          section         (log, layer->layerName, string("Layer: ") + layer->layerName);
+                       const vector<VkExtensionProperties>     properties      = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), layer->layerName);
+
+                       for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+                               log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+               }
+       }
+
+       return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus deviceFeatures (Context& context)
+{
+       TestLog&                                                log                     = context.getTestContext().getLog();
+       VkPhysicalDeviceFeatures*               features;
+       deUint8                                                 buffer[sizeof(VkPhysicalDeviceFeatures) + GUARD_SIZE];
+
+       deMemset(buffer, GUARD_VALUE, sizeof(buffer));
+       features = reinterpret_cast<VkPhysicalDeviceFeatures*>(buffer);
+
+       context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), features);
+
+       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+               << TestLog::Message << *features << TestLog::EndMessage;
+
+       for (int ndx = 0; ndx < GUARD_SIZE; ndx++)
+       {
+               if (buffer[ndx + sizeof(VkPhysicalDeviceFeatures)] != GUARD_VALUE)
+               {
+                       log << TestLog::Message << "deviceFeatures - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+                       return tcu::TestStatus::fail("deviceFeatures buffer overflow");
+               }
+       }
+
+       if (!validateInitComplete(context.getPhysicalDevice(), &InstanceInterface::getPhysicalDeviceFeatures, context.getInstanceInterface()))
+       {
+               log << TestLog::Message << "deviceFeatures - VkPhysicalDeviceFeatures not completely initialized" << TestLog::EndMessage;
+               return tcu::TestStatus::fail("deviceFeatures incomplete initialization");
+       }
+
+       return tcu::TestStatus::pass("Query succeeded");
+}
+
+tcu::TestStatus deviceProperties (Context& context)
+{
+       TestLog&                                                log                     = context.getTestContext().getLog();
+       VkPhysicalDeviceProperties*             props;
+       deUint8                                                 buffer[sizeof(VkPhysicalDeviceProperties) + GUARD_SIZE];
+
+       props = reinterpret_cast<VkPhysicalDeviceProperties*>(buffer);
+       deMemset(props, GUARD_VALUE, sizeof(buffer));
+
+       context.getInstanceInterface().getPhysicalDeviceProperties(context.getPhysicalDevice(), props);
+
+       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+               << TestLog::Message << *props << TestLog::EndMessage;
+
+       if (!validateFeatureLimits(props, log))
+               return tcu::TestStatus::fail("deviceProperties - feature limits failed");
+
+       for (int ndx = 0; ndx < GUARD_SIZE; ndx++)
+       {
+               if (buffer[ndx + sizeof(VkPhysicalDeviceProperties)] != GUARD_VALUE)
+               {
+                       log << TestLog::Message << "deviceProperties - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+                       return tcu::TestStatus::fail("deviceProperties buffer overflow");
+               }
+       }
+
+       if (!validateInitComplete(context.getPhysicalDevice(), &InstanceInterface::getPhysicalDeviceProperties, context.getInstanceInterface()))
+       {
+               log << TestLog::Message << "deviceProperties - VkPhysicalDeviceProperties not completely initialized" << TestLog::EndMessage;
+               return tcu::TestStatus::fail("deviceProperties incomplete initialization");
+       }
+
+       return tcu::TestStatus::pass("DeviceProperites query succeeded");
+}
+
+tcu::TestStatus deviceQueueFamilyProperties (Context& context)
+{
+       TestLog&                                                                log                                     = context.getTestContext().getLog();
+       const vector<VkQueueFamilyProperties>   queueProperties         = getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
+
+       for (size_t queueNdx = 0; queueNdx < queueProperties.size(); queueNdx++)
+               log << TestLog::Message << queueNdx << ": " << queueProperties[queueNdx] << TestLog::EndMessage;
+
+       return tcu::TestStatus::pass("Querying queue properties succeeded");
+}
+
+tcu::TestStatus deviceMemoryProperties (Context& context)
+{
+       TestLog&                                                        log                     = context.getTestContext().getLog();
+       VkPhysicalDeviceMemoryProperties*       memProps;
+       deUint8                                                         buffer[sizeof(VkPhysicalDeviceMemoryProperties) + GUARD_SIZE];
+
+       memProps = reinterpret_cast<VkPhysicalDeviceMemoryProperties*>(buffer);
+       deMemset(buffer, GUARD_VALUE, sizeof(buffer));
+
+       context.getInstanceInterface().getPhysicalDeviceMemoryProperties(context.getPhysicalDevice(), memProps);
+
+       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+               << TestLog::Message << *memProps << TestLog::EndMessage;
+
+       for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
+       {
+               if (buffer[ndx + sizeof(VkPhysicalDeviceMemoryProperties)] != GUARD_VALUE)
+               {
+                       log << TestLog::Message << "deviceMemoryProperties - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
+                       return tcu::TestStatus::fail("deviceMemoryProperties buffer overflow");
+               }
+       }
+
+       return tcu::TestStatus::pass("Querying memory properties succeeded");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createFeatureInfoTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> infoTests       (new tcu::TestCaseGroup(testCtx, "info", "Platform Information Tests"));
+
+       {
+               de::MovePtr<tcu::TestCaseGroup> instanceInfoTests       (new tcu::TestCaseGroup(testCtx, "instance", "Instance Information Tests"));
+
+               addFunctionCase(instanceInfoTests.get(), "physical_devices",            "Physical devices",                     enumeratePhysicalDevices);
+               addFunctionCase(instanceInfoTests.get(), "layers",                                      "Layers",                                       enumerateInstanceLayers);
+               addFunctionCase(instanceInfoTests.get(), "extensions",                          "Extensions",                           enumerateInstanceExtensions);
+
+               infoTests->addChild(instanceInfoTests.release());
+       }
+
+       {
+               de::MovePtr<tcu::TestCaseGroup> deviceInfoTests (new tcu::TestCaseGroup(testCtx, "device", "Device Information Tests"));
+
+               addFunctionCase(deviceInfoTests.get(), "features",                                      "Device Features",                      deviceFeatures);
+               addFunctionCase(deviceInfoTests.get(), "properties",                            "Device Properties",            deviceProperties);
+               addFunctionCase(deviceInfoTests.get(), "queue_family_properties",       "Queue family properties",      deviceQueueFamilyProperties);
+               addFunctionCase(deviceInfoTests.get(), "memory_properties",                     "Memory properties",            deviceMemoryProperties);
+               addFunctionCase(deviceInfoTests.get(), "layers",                                        "Layers",                                       enumerateDeviceLayers);
+               addFunctionCase(deviceInfoTests.get(), "extensions",                            "Extensions",                           enumerateDeviceExtensions);
+
+               infoTests->addChild(deviceInfoTests.release());
+       }
+
+       return infoTests.release();
+}
+
+} // api
+} // vkt
@@ -1,5 +1,5 @@
-#ifndef _VKTINFO_HPP
-#define _VKTINFO_HPP
+#ifndef _VKTAPIFEATUREINFO_HPP
+#define _VKTAPIFEATUREINFO_HPP
 /*-------------------------------------------------------------------------
  * Vulkan Conformance Tests
  * ------------------------
@@ -31,7 +31,7 @@
  *
  *//*!
  * \file
- * \brief Platform information tests
+ * \brief API Feature Query tests
  *//*--------------------------------------------------------------------*/
 
 #include "tcuDefs.hpp"
 
 namespace vkt
 {
+namespace api
+{
 
-tcu::TestCaseGroup*            createInfoTests         (tcu::TestContext& testCtx);
+tcu::TestCaseGroup*            createFeatureInfoTests          (tcu::TestContext& testCtx);
 
+} // api
 } // vkt
 
-#endif // _VKTINFO_HPP
+#endif // _VKTAPIFEATUREINFO_HPP
index 8ef1121..d992a37 100644 (file)
@@ -44,6 +44,7 @@
 #include "vkTypeUtil.hpp"
 #include "vkPlatform.hpp"
 #include "vkStrUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
 
 #include "tcuVector.hpp"
 #include "tcuResultCollector.hpp"
@@ -232,12 +233,13 @@ deUint32 getDefaultTestThreadCount (void)
 
 struct Environment
 {
-       const PlatformInterface&        vkp;
-       const DeviceInterface&          vkd;
-       VkDevice                                        device;
-       deUint32                                        queueFamilyIndex;
-       const BinaryCollection&         programBinaries;
-       deUint32                                        maxResourceConsumers;           // Maximum number of objects using same Object::Resources concurrently
+       const PlatformInterface&                vkp;
+       const DeviceInterface&                  vkd;
+       VkDevice                                                device;
+       deUint32                                                queueFamilyIndex;
+       const BinaryCollection&                 programBinaries;
+       const VkAllocationCallbacks*    allocationCallbacks;
+       deUint32                                                maxResourceConsumers;           // Maximum number of objects using same Object::Resources concurrently
 
        Environment (Context& context, deUint32 maxResourceConsumers_)
                : vkp                                   (context.getPlatformInterface())
@@ -245,21 +247,24 @@ struct Environment
                , device                                (context.getDevice())
                , queueFamilyIndex              (context.getUniversalQueueFamilyIndex())
                , programBinaries               (context.getBinaryCollection())
+               , allocationCallbacks   (DE_NULL)
                , maxResourceConsumers  (maxResourceConsumers_)
        {
        }
 
-       Environment (const PlatformInterface&   vkp_,
-                                const DeviceInterface&         vkd_,
-                                VkDevice                                       device_,
-                                deUint32                                       queueFamilyIndex_,
-                                const BinaryCollection&        programBinaries_,
-                                deUint32                                       maxResourceConsumers_)
+       Environment (const PlatformInterface&           vkp_,
+                                const DeviceInterface&                 vkd_,
+                                VkDevice                                               device_,
+                                deUint32                                               queueFamilyIndex_,
+                                const BinaryCollection&                programBinaries_,
+                                const VkAllocationCallbacks*   allocationCallbacks_,
+                                deUint32                                               maxResourceConsumers_)
                : vkp                                   (vkp_)
                , vkd                                   (vkd_)
                , device                                (device_)
                , queueFamilyIndex              (queueFamilyIndex_)
                , programBinaries               (programBinaries_)
+               , allocationCallbacks   (allocationCallbacks_)
                , maxResourceConsumers  (maxResourceConsumers_)
        {
        }
@@ -324,7 +329,7 @@ struct Instance
                        DE_NULL,                                                        // ppEnabledExtensionNames
                };
 
-               return createInstance(env.vkp, &instanceInfo);
+               return createInstance(env.vkp, &instanceInfo, env.allocationCallbacks);
        }
 };
 
@@ -386,7 +391,7 @@ struct Device
                }
        };
 
-       static Move<VkDevice> create (const Environment&, const Resources& res, const Parameters&)
+       static Move<VkDevice> create (const Environment& env, const Resources& res, const Parameters&)
        {
                const float     queuePriority   = 1.0;
 
@@ -415,7 +420,7 @@ struct Device
                        DE_NULL,                                                                // pEnabledFeatures
                };
 
-               return createDevice(res.vki, res.physicalDevice, &deviceInfo);
+               return createDevice(res.vki, res.physicalDevice, &deviceInfo, env.allocationCallbacks);
        }
 };
 
@@ -453,7 +458,7 @@ struct DeviceMemory
                        params.memoryTypeIndex
                };
 
-               return allocateMemory(env.vkd, env.device, &allocInfo);
+               return allocateMemory(env.vkd, env.device, &allocInfo, env.allocationCallbacks);
        }
 };
 
@@ -509,7 +514,7 @@ struct Buffer
                        &env.queueFamilyIndex
                };
 
-               return createBuffer(env.vkd, env.device, &bufferInfo);
+               return createBuffer(env.vkd, env.device, &bufferInfo, env.allocationCallbacks);
        }
 };
 
@@ -563,7 +568,7 @@ struct BufferView
                        params.range
                };
 
-               return createBufferView(env.vkd, env.device, &bufferViewInfo);
+               return createBufferView(env.vkd, env.device, &bufferViewInfo, env.allocationCallbacks);
        }
 };
 
@@ -635,7 +640,7 @@ struct Image
                        params.initialLayout
                };
 
-               return createImage(env.vkd, env.device, &imageInfo);
+               return createImage(env.vkd, env.device, &imageInfo, env.allocationCallbacks);
        }
 };
 
@@ -693,7 +698,7 @@ struct ImageView
                        params.subresourceRange,
                };
 
-               return createImageView(env.vkd, env.device, &imageViewInfo);
+               return createImageView(env.vkd, env.device, &imageViewInfo, env.allocationCallbacks);
        }
 };
 
@@ -726,7 +731,7 @@ struct Semaphore
                        params.flags
                };
 
-               return createSemaphore(env.vkd, env.device, &semaphoreInfo);
+               return createSemaphore(env.vkd, env.device, &semaphoreInfo, env.allocationCallbacks);
        }
 };
 
@@ -759,7 +764,7 @@ struct Fence
                        params.flags
                };
 
-               return createFence(env.vkd, env.device, &fenceInfo);
+               return createFence(env.vkd, env.device, &fenceInfo, env.allocationCallbacks);
        }
 };
 
@@ -792,7 +797,7 @@ struct Event
                        params.flags
                };
 
-               return createEvent(env.vkd, env.device, &eventInfo);
+               return createEvent(env.vkd, env.device, &eventInfo, env.allocationCallbacks);
        }
 };
 
@@ -834,7 +839,7 @@ struct QueryPool
                        params.pipelineStatistics
                };
 
-               return createQueryPool(env.vkd, env.device, &queryPoolInfo);
+               return createQueryPool(env.vkd, env.device, &queryPoolInfo, env.allocationCallbacks);
        }
 };
 
@@ -915,7 +920,7 @@ struct ShaderModule
                        (const deUint32*)res.binary.getBinary(),
                };
 
-               return createShaderModule(env.vkd, env.device, &shaderModuleInfo);
+               return createShaderModule(env.vkd, env.device, &shaderModuleInfo, env.allocationCallbacks);
        }
 };
 
@@ -946,7 +951,7 @@ struct PipelineCache
                        DE_NULL,                                                // pInitialData
                };
 
-               return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo);
+               return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo, env.allocationCallbacks);
        }
 };
 
@@ -1020,7 +1025,7 @@ struct Sampler
                        params.unnormalizedCoordinates
                };
 
-               return createSampler(env.vkd, env.device, &samplerInfo);
+               return createSampler(env.vkd, env.device, &samplerInfo, env.allocationCallbacks);
        }
 };
 
@@ -1125,7 +1130,7 @@ struct DescriptorSetLayout
                        (res.bindings.empty() ? DE_NULL : &res.bindings[0])
                };
 
-               return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo);
+               return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo, env.allocationCallbacks);
        }
 };
 
@@ -1188,7 +1193,7 @@ struct PipelineLayout
                        (params.pushConstantRanges.empty() ? DE_NULL : &params.pushConstantRanges[0]),
                };
 
-               return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo);
+               return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo, env.allocationCallbacks);
        }
 };
 
@@ -1276,7 +1281,7 @@ struct RenderPass
                        DE_NULL                                                                                 // pDependencies
                };
 
-               return createRenderPass(env.vkd, env.device, &renderPassInfo);
+               return createRenderPass(env.vkd, env.device, &renderPassInfo, env.allocationCallbacks);
        }
 };
 
@@ -1490,7 +1495,7 @@ struct GraphicsPipeline
                        0,                                                                              // basePipelineIndex
                };
 
-               return createGraphicsPipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+               return createGraphicsPipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo, env.allocationCallbacks);
        }
 };
 
@@ -1557,7 +1562,7 @@ struct ComputePipeline
                        0u,                                                     // basePipelineIndex
                };
 
-               return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+               return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo, env.allocationCallbacks);
        }
 };
 
@@ -1609,7 +1614,7 @@ struct DescriptorPool
                        (params.poolSizes.empty() ? DE_NULL : &params.poolSizes[0])
                };
 
-               return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo);
+               return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo, env.allocationCallbacks);
        }
 };
 
@@ -1742,7 +1747,7 @@ struct Framebuffer
                        1u                                                                                      // layers
                };
 
-               return createFramebuffer(env.vkd, env.device, &framebufferInfo);
+               return createFramebuffer(env.vkd, env.device, &framebufferInfo, env.allocationCallbacks);
        }
 };
 
@@ -1776,7 +1781,7 @@ struct CommandPool
                        env.queueFamilyIndex,
                };
 
-               return createCommandPool(env.vkd, env.device, &cmdPoolInfo);
+               return createCommandPool(env.vkd, env.device, &cmdPoolInfo, env.allocationCallbacks);
        }
 };
 
@@ -1971,11 +1976,17 @@ struct EnvClone
                : deviceRes     (parent, deviceParams)
                , device        (Device::create(parent, deviceRes, deviceParams))
                , vkd           (deviceRes.vki, *device)
-               , env           (parent.vkp, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, maxResourceConsumers)
+               , env           (parent.vkp, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, parent.allocationCallbacks, maxResourceConsumers)
        {
        }
 };
 
+Device::Parameters getDefaulDeviceParameters (Context& context)
+{
+       return Device::Parameters(context.getTestContext().getCommandLine().getVKDeviceId()-1u,
+                                                         VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
+}
+
 template<typename Object>
 tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typename Object::Parameters params)
 {
@@ -1983,7 +1994,7 @@ tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typena
        typedef SharedPtr<typename Object::Resources>   ResPtr;
 
        const deUint32                          numThreads              = getDefaultTestThreadCount();
-       const Device::Parameters        deviceParams    (context.getTestContext().getCommandLine().getVKDeviceId()-1u, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
+       const Device::Parameters        deviceParams    = getDefaulDeviceParameters(context);
        const Environment                       sharedEnv               (context, numThreads);                  // For creating Device's
        vector<EnvPtr>                          perThreadEnv    (numThreads);
        vector<ResPtr>                          resources               (numThreads);
@@ -2000,6 +2011,129 @@ tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typena
        return threads.run();
 }
 
+template<typename Object>
+tcu::TestStatus createSingleAllocCallbacksTest (Context& context, typename Object::Parameters params)
+{
+       const deUint32                                          noCmdScope              = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
+                                                                                                               | VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
+                                                                                                               | VK_SYSTEM_ALLOCATION_SCOPE_CACHE
+                                                                                                               | VK_SYSTEM_ALLOCATION_SCOPE_OBJECT;
+
+       // Callbacks used by resources
+       AllocationCallbackRecorder                      resCallbacks    (getSystemAllocator(), 128);
+
+       // Root environment still uses default instance and device, created without callbacks
+       const Environment                                       rootEnv                 (context.getPlatformInterface(),
+                                                                                                                context.getDeviceInterface(),
+                                                                                                                context.getDevice(),
+                                                                                                                context.getUniversalQueueFamilyIndex(),
+                                                                                                                context.getBinaryCollection(),
+                                                                                                                resCallbacks.getCallbacks(),
+                                                                                                                1u);
+
+       {
+               // Test env has instance & device created with callbacks
+               const EnvClone                                          resEnv          (rootEnv, getDefaulDeviceParameters(context), 1u);
+               const typename Object::Resources        res                     (resEnv.env, params);
+
+               // Supply a separate callback recorder just for object construction
+               AllocationCallbackRecorder                      objCallbacks(getSystemAllocator(), 128);
+               const Environment                                       objEnv          (resEnv.env.vkp,
+                                                                                                                resEnv.env.vkd,
+                                                                                                                resEnv.env.device,
+                                                                                                                resEnv.env.queueFamilyIndex,
+                                                                                                                resEnv.env.programBinaries,
+                                                                                                                objCallbacks.getCallbacks(),
+                                                                                                                resEnv.env.maxResourceConsumers);
+
+               {
+                       Unique<typename Object::Type>   obj     (Object::create(objEnv, res, params));
+
+                       // Validate that no command-level allocations are live
+                       if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, noCmdScope))
+                               return tcu::TestStatus::fail("Invalid allocation callback");
+               }
+
+               // At this point all allocations made against object callbacks must have been freed
+               if (!validateAndLog(context.getTestContext().getLog(), objCallbacks, 0u))
+                       return tcu::TestStatus::fail("Invalid allocation callback");
+       }
+
+       if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
+               return tcu::TestStatus::fail("Invalid allocation callback");
+
+       return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+tcu::TestStatus allocCallbackFailTest (Context& context, typename Object::Parameters params)
+{
+       AllocationCallbackRecorder                      resCallbacks    (getSystemAllocator(), 128);
+       const Environment                                       rootEnv                 (context.getPlatformInterface(),
+                                                                                                                context.getDeviceInterface(),
+                                                                                                                context.getDevice(),
+                                                                                                                context.getUniversalQueueFamilyIndex(),
+                                                                                                                context.getBinaryCollection(),
+                                                                                                                resCallbacks.getCallbacks(),
+                                                                                                                1u);
+
+       {
+               const EnvClone                                          resEnv                          (rootEnv, getDefaulDeviceParameters(context), 1u);
+               const typename Object::Resources        res                                     (resEnv.env, params);
+               deUint32                                                        numPassingAllocs        = 0;
+               const deUint32                                          maxTries                        = 1u<<10;
+
+               // Iterate over test until object allocation succeeds
+               for (; numPassingAllocs < maxTries; ++numPassingAllocs)
+               {
+                       DeterministicFailAllocator                      objAllocator(getSystemAllocator(), numPassingAllocs);
+                       AllocationCallbackRecorder                      recorder        (objAllocator.getCallbacks(), 128);
+                       const Environment                                       objEnv          (resEnv.env.vkp,
+                                                                                                                        resEnv.env.vkd,
+                                                                                                                        resEnv.env.device,
+                                                                                                                        resEnv.env.queueFamilyIndex,
+                                                                                                                        resEnv.env.programBinaries,
+                                                                                                                        recorder.getCallbacks(),
+                                                                                                                        resEnv.env.maxResourceConsumers);
+                       bool                                                            createOk        = false;
+
+                       context.getTestContext().getLog()
+                               << TestLog::Message
+                               << "Trying to create object with " << numPassingAllocs << " allocation" << (numPassingAllocs != 1 ? "s" : "") << " passing"
+                               << TestLog::EndMessage;
+
+                       try
+                       {
+                               Unique<typename Object::Type>   obj     (Object::create(objEnv, res, params));
+                               createOk = true;
+                       }
+                       catch (const vk::OutOfMemoryError& e)
+                       {
+                               if (e.getError() != VK_ERROR_OUT_OF_HOST_MEMORY)
+                               {
+                                       context.getTestContext().getLog() << e;
+                                       return tcu::TestStatus::fail("Got invalid error code");
+                               }
+                       }
+
+                       if (!validateAndLog(context.getTestContext().getLog(), recorder, 0u))
+                               return tcu::TestStatus::fail("Invalid allocation callback");
+
+                       if (createOk)
+                       {
+                               context.getTestContext().getLog()
+                                       << TestLog::Message << "Object construction succeeded! " << TestLog::EndMessage;
+                               break;
+                       }
+               }
+       }
+
+       if (!validateAndLog(context.getTestContext().getLog(), resCallbacks, 0u))
+               return tcu::TestStatus::fail("Invalid allocation callback");
+
+       return tcu::TestStatus::pass("Ok");
+}
+
 // Utilities for creating groups
 
 template<typename Object>
@@ -2436,6 +2570,64 @@ tcu::TestCaseGroup* createObjectManagementTests (tcu::TestContext& testCtx)
        };
        objectMgmtTests->addChild(createGroup(testCtx, "multithreaded_shared_resources", "Multithreaded object construction with shared resources", s_multithreadedCreateSharedResourcesGroup));
 
+       static const CaseDescriptions   s_createSingleAllocCallbacksGroup       =
+       {
+               CASE_DESC(createSingleAllocCallbacksTest        <Instance>,                                     s_instanceCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Device>,                                       s_deviceCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <DeviceMemory>,                         s_deviceMemCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Buffer>,                                       s_bufferCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <BufferView>,                           s_bufferViewCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Image>,                                        s_imageCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <ImageView>,                            s_imageViewCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Semaphore>,                            s_semaphoreCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Event>,                                        s_eventCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Fence>,                                        s_fenceCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <QueryPool>,                            s_queryPoolCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <ShaderModule>,                         s_shaderModuleCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <PipelineCache>,                        s_pipelineCacheCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <PipelineLayout>,                       s_pipelineLayoutCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <RenderPass>,                           s_renderPassCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <GraphicsPipeline>,                     s_graphicsPipelineCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <ComputePipeline>,                      s_computePipelineCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <DescriptorSetLayout>,          s_descriptorSetLayoutCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Sampler>,                                      s_samplerCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <DescriptorPool>,                       s_descriptorPoolCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <DescriptorSet>,                        s_descriptorSetCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <Framebuffer>,                          s_framebufferCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <CommandPool>,                          s_commandPoolCases),
+               CASE_DESC(createSingleAllocCallbacksTest        <CommandBuffer>,                        s_commandBufferCases),
+       };
+       objectMgmtTests->addChild(createGroup(testCtx, "single_alloc_callbacks", "Create single object", s_createSingleAllocCallbacksGroup));
+
+       static const CaseDescriptions   s_allocCallbackFailGroup        =
+       {
+               CASE_DESC(allocCallbackFailTest <Instance>,                                     s_instanceCases),
+               CASE_DESC(allocCallbackFailTest <Device>,                                       s_deviceCases),
+               CASE_DESC(allocCallbackFailTest <DeviceMemory>,                         s_deviceMemCases),
+               CASE_DESC(allocCallbackFailTest <Buffer>,                                       s_bufferCases),
+               CASE_DESC(allocCallbackFailTest <BufferView>,                           s_bufferViewCases),
+               CASE_DESC(allocCallbackFailTest <Image>,                                        s_imageCases),
+               CASE_DESC(allocCallbackFailTest <ImageView>,                            s_imageViewCases),
+               CASE_DESC(allocCallbackFailTest <Semaphore>,                            s_semaphoreCases),
+               CASE_DESC(allocCallbackFailTest <Event>,                                        s_eventCases),
+               CASE_DESC(allocCallbackFailTest <Fence>,                                        s_fenceCases),
+               CASE_DESC(allocCallbackFailTest <QueryPool>,                            s_queryPoolCases),
+               CASE_DESC(allocCallbackFailTest <ShaderModule>,                         s_shaderModuleCases),
+               CASE_DESC(allocCallbackFailTest <PipelineCache>,                        s_pipelineCacheCases),
+               CASE_DESC(allocCallbackFailTest <PipelineLayout>,                       s_pipelineLayoutCases),
+               CASE_DESC(allocCallbackFailTest <RenderPass>,                           s_renderPassCases),
+               CASE_DESC(allocCallbackFailTest <GraphicsPipeline>,                     s_graphicsPipelineCases),
+               CASE_DESC(allocCallbackFailTest <ComputePipeline>,                      s_computePipelineCases),
+               CASE_DESC(allocCallbackFailTest <DescriptorSetLayout>,          s_descriptorSetLayoutCases),
+               CASE_DESC(allocCallbackFailTest <Sampler>,                                      s_samplerCases),
+               CASE_DESC(allocCallbackFailTest <DescriptorPool>,                       s_descriptorPoolCases),
+               CASE_DESC(allocCallbackFailTest <DescriptorSet>,                        s_descriptorSetCases),
+               CASE_DESC(allocCallbackFailTest <Framebuffer>,                          s_framebufferCases),
+               CASE_DESC(allocCallbackFailTest <CommandPool>,                          s_commandPoolCases),
+               CASE_DESC(allocCallbackFailTest <CommandBuffer>,                        s_commandBufferCases),
+       };
+       objectMgmtTests->addChild(createGroup(testCtx, "alloc_callback_fail", "Allocation callback failure", s_allocCallbackFailGroup));
+
        return objectMgmtTests.release();
 }
 
index 47ed995..b751dd6 100644 (file)
@@ -42,6 +42,7 @@
 #include "vktApiBufferTests.hpp"
 #include "vktApiBufferViewCreateTests.hpp"
 #include "vktApiBufferViewAccessTests.hpp"
+#include "vktApiFeatureInfo.hpp"
 
 namespace vkt
 {
@@ -68,6 +69,7 @@ tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
        de::MovePtr<tcu::TestCaseGroup> apiTests        (new tcu::TestCaseGroup(testCtx, "api", "API Tests"));
 
        apiTests->addChild(createSmokeTests                                     (testCtx));
+       apiTests->addChild(api::createFeatureInfoTests          (testCtx));
        apiTests->addChild(createDeviceInitializationTests      (testCtx));
        apiTests->addChild(createObjectManagementTests          (testCtx));
        apiTests->addChild(createBufferTests                            (testCtx));
index 7c2ed33..f112284 100644 (file)
@@ -4042,20 +4042,20 @@ vk::Move<vk::VkSampler> ImageSampleInstanceImages::createSampler (const vk::Devi
                vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
                DE_NULL,
                (vk::VkSamplerCreateFlags)0,
-               vk::mapFilterMode(sampler.magFilter),                   // magFilter
-               vk::mapFilterMode(sampler.minFilter),                   // minFilter
-               vk::mapMipmapMode(sampler.minFilter),                   // mipMode
-               vk::mapWrapMode(sampler.wrapS),                                 // addressU
-               vk::mapWrapMode(sampler.wrapT),                                 // addressV
-               vk::mapWrapMode(sampler.wrapR),                                 // addressW
-               0.0f,                                                                                   // mipLodBias
-               1,                                                                                              // maxAnisotropy
-               (compareEnabled ? vk::VK_TRUE : vk::VK_FALSE),  // compareEnable
-               compareOp,                                                                              // compareOp
-               0.0f,                                                                                   // minLod
-               0.0f,                                                                                   // maxLod
-               borderColor,                                                                    // borderColor
-               vk::VK_FALSE,                                                                   // unnormalizedCoords
+               vk::mapFilterMode(sampler.magFilter),                                                   // magFilter
+               vk::mapFilterMode(sampler.minFilter),                                                   // minFilter
+               vk::mapMipmapMode(sampler.minFilter),                                                   // mipMode
+               vk::mapWrapMode(sampler.wrapS),                                                                 // addressU
+               vk::mapWrapMode(sampler.wrapT),                                                                 // addressV
+               vk::mapWrapMode(sampler.wrapR),                                                                 // addressW
+               0.0f,                                                                                                                   // mipLodBias
+               1,                                                                                                                              // maxAnisotropy
+               (vk::VkBool32)(compareEnabled ? vk::VK_TRUE : vk::VK_FALSE),    // compareEnable
+               compareOp,                                                                                                              // compareOp
+               0.0f,                                                                                                                   // minLod
+               0.0f,                                                                                                                   // maxLod
+               borderColor,                                                                                                    // borderColor
+               vk::VK_FALSE,                                                                                                   // unnormalizedCoords
        };
        return vk::createSampler(vki, device, &createInfo);
 }
index d256c4a..281a95f 100644 (file)
@@ -8,16 +8,23 @@ set(DEQP_VK_PIPELINE_SRCS
        vktPipelineBlendTests.hpp
        vktPipelineClearUtil.cpp
        vktPipelineClearUtil.hpp
+       vktPipelineCombinationsIterator.hpp
        vktPipelineDepthTests.cpp
        vktPipelineDepthTests.hpp
        vktPipelineImageSamplingInstance.cpp
        vktPipelineImageSamplingInstance.hpp
        vktPipelineImageTests.cpp
        vktPipelineImageTests.hpp
+       vktPipelinePushConstantTests.cpp
+       vktPipelinePushConstantTests.hpp
        vktPipelineImageUtil.cpp
        vktPipelineImageUtil.hpp
        vktPipelineImageViewTests.cpp
        vktPipelineImageViewTests.hpp
+       vktPipelineMultisampleTests.cpp
+       vktPipelineMultisampleTests.hpp
+       vktPipelineInputAssemblyTests.cpp
+       vktPipelineInputAssemblyTests.hpp
        vktPipelineReferenceRenderer.cpp
        vktPipelineReferenceRenderer.hpp
        vktPipelineSamplerTests.cpp
@@ -26,6 +33,9 @@ set(DEQP_VK_PIPELINE_SRCS
        vktPipelineStencilTests.hpp
        vktPipelineTests.cpp
        vktPipelineTests.hpp
+       vktPipelineUniqueRandomIterator.hpp
+       vktPipelineVertexInputTests.cpp
+       vktPipelineVertexInputTests.hpp
        vktPipelineVertexUtil.cpp
        vktPipelineVertexUtil.hpp
        )
index 92bc6df..7d8c89c 100644 (file)
@@ -866,7 +866,7 @@ tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& forma
 
                case TextureFormat::UNORM_INT_1010102_REV:
                case TextureFormat::SNORM_INT_1010102_REV:
-                       threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.1f);
+                       threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.34f);
                        break;
 
                case TextureFormat::UNORM_INT8:
@@ -893,7 +893,7 @@ tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& forma
                        break;
 
                case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
-                       threshold = Vec4(0.02f, 0.02f, 0.02f, 1.0f);
+                       threshold = Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
                        break;
 
                case TextureFormat::UNSIGNED_INT_999_E5_REV:
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineCombinationsIterator.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineCombinationsIterator.hpp
new file mode 100644 (file)
index 0000000..663847c
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+#define _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Iterator over combinations of items without repetition
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "deRandom.hpp"
+#include <set>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+template <typename T>
+class CombinationsIterator
+{
+public:
+                                                       CombinationsIterator    (deUint32 numItems, deUint32 combinationSize);
+       virtual                                 ~CombinationsIterator   (void) {}
+       bool                                    hasNext                                 (void) const;
+       T                                               next                                    (void);
+       void                                    reset                                   (void);
+
+protected:
+       virtual T                               getCombinationValue             (const std::vector<deUint32>& combination) = 0;
+
+private:
+       static deUint32                 factorial                               (deUint32 x);
+       deUint32                                m_numItems;
+
+       deUint32                                m_combinationIndex;
+       deUint32                                m_combinationSize;
+       deUint32                                m_combinationCount;
+
+       std::vector<deUint32>   m_combination;
+};
+
+static deUint32 seriesProduct (deUint32 first, deUint32 last)
+{
+       deUint32 result = 1;
+
+       for (deUint32 i = first; i <= last; i++)
+               result *= i;
+
+       return result;
+}
+
+template <typename T>
+CombinationsIterator<T>::CombinationsIterator (deUint32 numItems, deUint32 combinationSize)
+       : m_numItems            (numItems)
+       , m_combinationSize     (combinationSize)
+{
+       DE_ASSERT(m_combinationSize > 0);
+       DE_ASSERT(m_combinationSize <= m_numItems);
+
+       m_combinationCount      = seriesProduct(numItems - combinationSize + 1, numItems) / seriesProduct(1, combinationSize);
+
+       m_combination.resize(m_combinationSize);
+       reset();
+}
+
+template <typename T>
+bool CombinationsIterator<T>::hasNext (void) const
+{
+       return m_combinationIndex < m_combinationCount;
+}
+
+template <typename T>
+T CombinationsIterator<T>::next (void)
+{
+       DE_ASSERT(m_combinationIndex < m_combinationCount);
+
+       if (m_combinationIndex > 0)
+       {
+               for (int combinationItemNdx = (int)m_combinationSize - 1; combinationItemNdx >= 0; combinationItemNdx--)
+               {
+                       if ((m_combination[combinationItemNdx] + 1 < m_numItems) && ((combinationItemNdx == (int)m_combinationSize - 1) || (m_combination[combinationItemNdx + 1] > m_combination[combinationItemNdx] + 1)))
+                       {
+                               m_combination[combinationItemNdx]++;
+
+                               for (deUint32 resetNdx = combinationItemNdx + 1; resetNdx < m_combinationSize; resetNdx++)
+                                       m_combination[resetNdx] = m_combination[resetNdx - 1] + 1;
+
+                               break;
+                       }
+               }
+       }
+
+       m_combinationIndex++;
+
+       return getCombinationValue(m_combination);
+}
+
+template <typename T>
+void CombinationsIterator<T>::reset (void)
+{
+       // Set up first combination
+       for (deUint32 itemNdx = 0; itemNdx < m_combinationSize; itemNdx++)
+               m_combination[itemNdx] = itemNdx;
+
+       m_combinationIndex = 0;
+}
+
+template <typename T>
+deUint32 CombinationsIterator<T>::factorial (deUint32 x)
+{
+       deUint32 result = 1;
+
+       for (deUint32 value = x; value > 1; value--)
+               result *= value;
+
+       return result;
+}
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
index 9d847f2..c5601e6 100644 (file)
@@ -169,7 +169,25 @@ void copySubresourceRange<tcu::Texture1DArray> (tcu::Texture1DArray& dest, const
        }
 }
 
-static MovePtr<Program> createRefProgram (const tcu::TextureFormat&                    renderTargetFormat,
+template<>
+void copySubresourceRange<tcu::Texture3D>(tcu::Texture3D& dest, const tcu::Texture3D& src, const VkImageSubresourceRange& subresourceRange)
+{
+       DE_ASSERT(subresourceRange.levelCount <= (deUint32)dest.getNumLevels());
+       DE_ASSERT(subresourceRange.baseMipLevel + subresourceRange.levelCount <= (deUint32)src.getNumLevels());
+
+       for (int levelNdx = 0; levelNdx < dest.getNumLevels(); levelNdx++)
+       {
+               const tcu::ConstPixelBufferAccess       srcLevel(src.getLevel(subresourceRange.baseMipLevel + levelNdx));
+               const tcu::ConstPixelBufferAccess       srcLevelLayers(srcLevel.getFormat(), srcLevel.getWidth(), srcLevel.getHeight(), srcLevel.getDepth(), (deUint8*)srcLevel.getDataPtr());
+
+               if (dest.isLevelEmpty(levelNdx))
+                       dest.allocLevel(levelNdx);
+
+               tcu::copy(dest.getLevel(levelNdx), srcLevelLayers);
+       }
+}
+
+static MovePtr<Program> createRefProgram(const tcu::TextureFormat&                     renderTargetFormat,
                                                                                  const tcu::Sampler&                           sampler,
                                                                                  float                                                         samplerLod,
                                                                                  const tcu::UVec4&                                     componentMapping,
@@ -278,7 +296,21 @@ static MovePtr<Program> createRefProgram (const tcu::TextureFormat&                        renderTarg
                case VK_IMAGE_TYPE_3D:
                        {
                                const tcu::Texture3D& texture = dynamic_cast<const TestTexture3D&>(testTexture).getTexture();
-                               program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, texture, sampler, samplerLod, componentMapping));
+
+                               if (subresource.baseMipLevel > 0)
+                               {
+                                       // Not all texture levels are needed. Create new sub-texture.
+                                       const tcu::ConstPixelBufferAccess       baseLevel = texture.getLevel(subresource.baseMipLevel);
+                                       tcu::Texture3D                                          textureView(texture.getFormat(), baseLevel.getWidth(), baseLevel.getHeight(), baseLevel.getDepth());
+
+                                       copySubresourceRange(textureView, texture, subresource);
+
+                                       program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, textureView, sampler, samplerLod, componentMapping));
+                               }
+                               else
+                               {
+                                       program = MovePtr<Program>(new SamplerProgram<tcu::Texture3D>(renderTargetFormat, texture, sampler, samplerLod, componentMapping));
+                               }
                        }
                        break;
 
@@ -904,10 +936,7 @@ tcu::TestStatus ImageSamplingInstance::verifyImage (void)
        MovePtr<ReferenceRenderer>              refRenderer;
 
        // Set up LOD of reference sampler
-       if (m_samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_BASE)
-               samplerLod = 0.0f;
-       else
-               samplerLod = de::max(m_samplerParams.minLod, de::min(m_samplerParams.maxLod, m_samplerParams.mipLodBias + m_samplerLod));
+       samplerLod = de::max(m_samplerParams.minLod, de::min(m_samplerParams.maxLod, m_samplerParams.mipLodBias + m_samplerLod));
 
        // Create reference program that uses image subresource range
        program = createRefProgram(colorFormat, sampler, samplerLod, componentMapping, *m_texture, m_imageViewType, m_layerCount, m_subresourceRange);
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.cpp
new file mode 100644 (file)
index 0000000..1ac1e5a
--- /dev/null
@@ -0,0 +1,1629 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Input Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineInputAssemblyTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deMath.h"
+#include "deMemory.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+class InputAssemblyTest : public vkt::TestCase
+{
+public:
+       const static VkPrimitiveTopology        s_primitiveTopologies[];
+       const static deUint32                           s_restartIndex32;
+       const static deUint16                           s_restartIndex16;
+
+                                                                               InputAssemblyTest               (tcu::TestContext&              testContext,
+                                                                                                                                const std::string&             name,
+                                                                                                                                const std::string&             description,
+                                                                                                                                VkPrimitiveTopology    primitiveTopology,
+                                                                                                                                int                                    primitiveCount,
+                                                                                                                                bool                                   testPrimitiveRestart,
+                                                                                                                                VkIndexType                    indexType);
+       virtual                                                         ~InputAssemblyTest              (void) {}
+       virtual void                                            initPrograms                    (SourceCollections& sourceCollections) const;
+       virtual TestInstance*                           createInstance                  (Context& context) const;
+       static bool                                                     isRestartIndex                  (VkIndexType indexType, deUint32 indexValue);
+       static deUint32                                         getRestartIndex                 (VkIndexType indexType);
+
+protected:
+       virtual void                                            createBufferData                (VkPrimitiveTopology            topology,
+                                                                                                                                int                                            primitiveCount,
+                                                                                                                                VkIndexType                            indexType,
+                                                                                                                                std::vector<deUint32>&         indexData,
+                                                                                                                                std::vector<Vertex4RGBA>&      vertexData) const = 0;
+
+private:
+       VkPrimitiveTopology                                     m_primitiveTopology;
+       const int                                                       m_primitiveCount;
+       bool                                                            m_testPrimitiveRestart;
+       VkIndexType                                                     m_indexType;
+};
+
+class PrimitiveTopologyTest : public InputAssemblyTest
+{
+public:
+                                                                               PrimitiveTopologyTest   (tcu::TestContext&              testContext,
+                                                                                                                                const std::string&             name,
+                                                                                                                                const std::string&             description,
+                                                                                                                                VkPrimitiveTopology    primitiveTopology);
+       virtual                                                         ~PrimitiveTopologyTest  (void) {}
+
+protected:
+       virtual void                                            createBufferData                (VkPrimitiveTopology            topology,
+                                                                                                                                int                                            primitiveCount,
+                                                                                                                                VkIndexType                            indexType,
+                                                                                                                                std::vector<deUint32>&         indexData,
+                                                                                                                                std::vector<Vertex4RGBA>&      vertexData) const;
+
+private:
+};
+
+class PrimitiveRestartTest : public InputAssemblyTest
+{
+public:
+                                                                               PrimitiveRestartTest    (tcu::TestContext&              testContext,
+                                                                                                                                const std::string&             name,
+                                                                                                                                const std::string&             description,
+                                                                                                                                VkPrimitiveTopology    primitiveTopology,
+                                                                                                                                VkIndexType                    indexType);
+       virtual                                                         ~PrimitiveRestartTest   (void) {}
+
+protected:
+       virtual void                                            createBufferData                (VkPrimitiveTopology            topology,
+                                                                                                                                int                                            primitiveCount,
+                                                                                                                                VkIndexType                            indexType,
+                                                                                                                                std::vector<deUint32>&         indexData,
+                                                                                                                                std::vector<Vertex4RGBA>&      vertexData) const;
+
+private:
+       bool                                                            isRestartPrimitive              (int primitiveIndex) const;
+
+       std::vector<deUint32>                           m_restartPrimitives;
+};
+
+class InputAssemblyInstance : public vkt::TestInstance
+{
+public:
+                                                                               InputAssemblyInstance   (Context&                                                       context,
+                                                                                                                                VkPrimitiveTopology                            primitiveTopology,
+                                                                                                                                bool                                                           testPrimitiveRestart,
+                                                                                                                                VkIndexType                                            indexType,
+                                                                                                                                const std::vector<deUint32>&           indexBufferData,
+                                                                                                                                const std::vector<Vertex4RGBA>&        vertexBufferData);
+       virtual                                                         ~InputAssemblyInstance  (void);
+       virtual tcu::TestStatus                         iterate                                 (void);
+
+private:
+       tcu::TestStatus                                         verifyImage                             (void);
+       void                                                            uploadIndexBufferData16 (deUint16* destPtr, const std::vector<deUint32>& indexBufferData);
+
+       VkPrimitiveTopology                                     m_primitiveTopology;
+       bool                                                            m_primitiveRestartEnable;
+       VkIndexType                                                     m_indexType;
+
+       Move<VkBuffer>                                          m_vertexBuffer;
+       std::vector<Vertex4RGBA>                        m_vertices;
+       de::MovePtr<Allocation>                         m_vertexBufferAlloc;
+
+       Move<VkBuffer>                                          m_indexBuffer;
+       std::vector<deUint32>                           m_indices;
+       de::MovePtr<Allocation>                         m_indexBufferAlloc;
+
+       const tcu::IVec2                                        m_renderSize;
+
+       const VkFormat                                          m_colorFormat;
+       VkImageCreateInfo                                       m_colorImageCreateInfo;
+       Move<VkImage>                                           m_colorImage;
+       de::MovePtr<Allocation>                         m_colorImageAlloc;
+       Move<VkImageView>                                       m_colorAttachmentView;
+       Move<VkRenderPass>                                      m_renderPass;
+       Move<VkFramebuffer>                                     m_framebuffer;
+
+       Move<VkShaderModule>                            m_vertexShaderModule;
+       Move<VkShaderModule>                            m_fragmentShaderModule;
+
+       Move<VkPipelineLayout>                          m_pipelineLayout;
+       Move<VkPipeline>                                        m_graphicsPipeline;
+
+       Move<VkCommandPool>                                     m_cmdPool;
+       Move<VkCommandBuffer>                           m_cmdBuffer;
+
+       Move<VkFence>                                           m_fence;
+};
+
+
+// InputAssemblyTest
+
+const VkPrimitiveTopology InputAssemblyTest::s_primitiveTopologies[] =
+{
+       VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+       VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
+       VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
+       VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
+       VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
+       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
+       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
+};
+
+const deUint32 InputAssemblyTest::s_restartIndex32     = ~((deUint32)0u);
+const deUint16 InputAssemblyTest::s_restartIndex16     = ~((deUint16)0u);
+
+InputAssemblyTest::InputAssemblyTest (tcu::TestContext&                testContext,
+                                                                         const std::string&    name,
+                                                                         const std::string&    description,
+                                                                         VkPrimitiveTopology   primitiveTopology,
+                                                                         int                                   primitiveCount,
+                                                                         bool                                  testPrimitiveRestart,
+                                                                         VkIndexType                   indexType)
+
+       : vkt::TestCase                         (testContext, name, description)
+       , m_primitiveTopology           (primitiveTopology)
+       , m_primitiveCount                      (primitiveCount)
+       , m_testPrimitiveRestart        (testPrimitiveRestart)
+       , m_indexType                           (indexType)
+{
+}
+
+TestInstance* InputAssemblyTest::createInstance (Context& context) const
+{
+       std::vector<deUint32>           indexBufferData;
+       std::vector<Vertex4RGBA>        vertexBufferData;
+
+       createBufferData(m_primitiveTopology, m_primitiveCount, m_indexType, indexBufferData, vertexBufferData);
+
+       return new InputAssemblyInstance(context, m_primitiveTopology, m_testPrimitiveRestart, m_indexType, indexBufferData, vertexBufferData);
+}
+
+void InputAssemblyTest::initPrograms (SourceCollections& sourceCollections) const
+{
+       std::ostringstream vertexSource;
+
+       vertexSource <<
+               "#version 310 es\n"
+               "layout(location = 0) in vec4 position;\n"
+               "layout(location = 1) in vec4 color;\n"
+               "layout(location = 0) out highp vec4 vtxColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "       gl_Position = position;\n"
+               << (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? " gl_PointSize = 3.0;\n"
+                                                                                                                                       : "" )
+               << "    vtxColor = color;\n"
+               "}\n";
+
+       sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
+
+       sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
+               "#version 310 es\n"
+               "layout(location = 0) in highp vec4 vtxColor;\n"
+               "layout(location = 0) out highp vec4 fragColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "       fragColor = vtxColor;\n"
+               "}\n");
+}
+
+bool InputAssemblyTest::isRestartIndex (VkIndexType indexType, deUint32 indexValue)
+{
+       if (indexType == VK_INDEX_TYPE_UINT32)
+               return indexValue == s_restartIndex32;
+       else
+               return indexValue == s_restartIndex16;
+}
+
+deUint32 InputAssemblyTest::getRestartIndex (VkIndexType indexType)
+{
+       if (indexType == VK_INDEX_TYPE_UINT16)
+               return InputAssemblyTest::s_restartIndex16;
+       else
+               return InputAssemblyTest::s_restartIndex32;
+}
+
+
+// PrimitiveTopologyTest
+
+PrimitiveTopologyTest::PrimitiveTopologyTest (tcu::TestContext&                testContext,
+                                                                                         const std::string&    name,
+                                                                                         const std::string&    description,
+                                                                                         VkPrimitiveTopology   primitiveTopology)
+       : InputAssemblyTest     (testContext, name, description, primitiveTopology, 10, false, VK_INDEX_TYPE_UINT32)
+{
+}
+
+void PrimitiveTopologyTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
+{
+       DE_ASSERT(primitiveCount > 0);
+       DE_UNREF(indexType);
+
+       const tcu::Vec4                         red                                             (1.0f, 0.0f, 0.0f, 1.0f);
+       const tcu::Vec4                         green                                   (0.0f, 1.0f, 0.0f, 1.0f);
+       const float                                     border                                  = 0.2f;
+       const float                                     originX                                 = -1.0f + border;
+       const float                                     originY                                 = -1.0f + border;
+       const Vertex4RGBA                       defaultVertex                   = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
+       float                                           primitiveSizeY                  = (2.0f - 2.0f * border);
+       float                                           primitiveSizeX;
+       std::vector<deUint32>           indices;
+       std::vector<Vertex4RGBA>        vertices;
+
+
+       // Calculate primitive size
+       switch (topology)
+       {
+               case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
+               case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount - 1);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount + primitiveCount / 2 + primitiveCount % 2 - 1);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+                       primitiveSizeX = 1.0f - border;
+                       primitiveSizeY = 1.0f - border;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       switch (topology)
+       {
+               case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               const Vertex4RGBA vertex =
+                               {
+                                       tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                       red
+                               };
+
+                               vertices.push_back(vertex);
+                               indices.push_back(primitiveNdx);
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((primitiveNdx * 2 + vertexNdx));
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (primitiveNdx == 0)
+                               {
+                                       Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX, originY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(0);
+
+                                       vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
+                                       vertices.push_back(vertex);
+                                       indices.push_back(1);
+                               }
+                               else
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx + 1);
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx * 3 + vertexNdx);
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (primitiveNdx == 0)
+                               {
+                                       for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+                                       {
+                                               const Vertex4RGBA vertex =
+                                               {
+                                                       tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                       red
+                                               };
+
+                                               vertices.push_back(vertex);
+                                               indices.push_back(vertexNdx);
+                                       }
+                               }
+                               else
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx + 2);
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+               {
+                       const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (primitiveNdx == 0)
+                               {
+                                       Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(0);
+
+                                       vertex.position = tcu::Vec4(primitiveSizeX, 0.0f, 0.0f, 1.0f);
+                                       vertices.push_back(vertex);
+                                       indices.push_back(1);
+
+                                       vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle), primitiveSizeY * deFloatSin(stepAngle), 0.0f, 1.0f);
+                                       vertices.push_back(vertex);
+                                       indices.push_back(2);
+                               }
+                               else
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx + 2);
+                               }
+                       }
+                       break;
+               }
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               indices.push_back(0);
+
+                               for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx * 2 + vertexNdx + 1);
+                               }
+
+                               indices.push_back(0);
+                       }
+                       break;
+
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+                       indices.push_back(0);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (primitiveNdx == 0)
+                               {
+                                       Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX, originY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(1);
+
+                                       vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
+                                       vertices.push_back(vertex);
+                                       indices.push_back(2);
+                               }
+                               else
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx + 2);
+                               }
+                       }
+
+                       indices.push_back(0);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx * 3 + vertexNdx + 1);
+                                       indices.push_back(0);
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (primitiveNdx == 0)
+                               {
+                                       for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+                                       {
+                                               const Vertex4RGBA vertex =
+                                               {
+                                                       tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                       red
+                                               };
+
+                                               vertices.push_back(vertex);
+                                               indices.push_back(vertexNdx + 1);
+                                               indices.push_back(0);
+                                       }
+                               }
+                               else
+                               {
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back(primitiveNdx + 2 + 1);
+                                       indices.push_back(0);
+                               }
+                       }
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+                       break;
+       }
+
+       vertexData      = vertices;
+       indexData       = indices;
+}
+
+
+// PrimitiveRestartTest
+
+PrimitiveRestartTest::PrimitiveRestartTest (tcu::TestContext&          testContext,
+                                                                                       const std::string&              name,
+                                                                                       const std::string&              description,
+                                                                                       VkPrimitiveTopology             primitiveTopology,
+                                                                                       VkIndexType                             indexType)
+
+       : InputAssemblyTest     (testContext, name, description, primitiveTopology, 10, true, indexType)
+{
+       DE_ASSERT(primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ||
+                         primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ||
+                         primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN ||
+                         primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
+                         primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY);
+
+       deUint32 restartPrimitives[] = { 1, 5 };
+
+       m_restartPrimitives = std::vector<deUint32>(restartPrimitives, restartPrimitives + sizeof(restartPrimitives) / sizeof(deUint32));
+}
+
+void PrimitiveRestartTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
+{
+       DE_ASSERT(primitiveCount > 0);
+       DE_UNREF(indexType);
+
+       const tcu::Vec4                         red                                             (1.0f, 0.0f, 0.0f, 1.0f);
+       const tcu::Vec4                         green                                   (0.0f, 1.0f, 0.0f, 1.0f);
+       const float                                     border                                  = 0.2f;
+       const float                                     originX                                 = -1.0f + border;
+       const float                                     originY                                 = -1.0f + border;
+       const Vertex4RGBA                       defaultVertex                   = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
+       float                                           primitiveSizeY                  = (2.0f - 2.0f * border);
+       float                                           primitiveSizeX;
+       bool                                            primitiveStart                  = true;
+       std::vector<deUint32>           indices;
+       std::vector<Vertex4RGBA>        vertices;
+
+
+       // Calculate primitive size
+       switch (topology)
+       {
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+                       primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+                       primitiveSizeX = 1.0f - border;
+                       primitiveSizeY = 1.0f - border;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       switch (topology)
+       {
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (isRestartPrimitive(primitiveNdx))
+                               {
+                                       indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+                                       primitiveStart = true;
+                               }
+                               else
+                               {
+                                       if (primitiveStart)
+                                       {
+                                               const Vertex4RGBA vertex =
+                                               {
+                                                       tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                       red
+                                               };
+
+                                               vertices.push_back(vertex);
+                                               indices.push_back((deUint32)vertices.size() - 1);
+
+                                               primitiveStart = false;
+                                       }
+
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((deUint32)vertices.size() - 1);
+                               }
+                       }
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+               {
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (isRestartPrimitive(primitiveNdx))
+                               {
+                                       indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+                                       primitiveStart = true;
+                               }
+                               else
+                               {
+                                       if (primitiveStart)
+                                       {
+                                               for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+                                               {
+                                                       const Vertex4RGBA vertex =
+                                                       {
+                                                               tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                               red
+                                                       };
+
+                                                       vertices.push_back(vertex);
+                                                       indices.push_back((deUint32)vertices.size() - 1);
+                                               }
+
+                                               primitiveStart = false;
+                                       }
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((deUint32)vertices.size() - 1);
+                               }
+                       }
+                       break;
+               }
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+               {
+                       const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (isRestartPrimitive(primitiveNdx))
+                               {
+                                       indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+                                       primitiveStart = true;
+                               }
+                               else
+                               {
+                                       if (primitiveStart)
+                                       {
+                                               Vertex4RGBA vertex =
+                                               {
+                                                       tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+                                                       red
+                                               };
+
+                                               vertices.push_back(vertex);
+                                               indices.push_back((deUint32)vertices.size() - 1);
+
+                                               vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx)), 0.0f, 1.0f),
+                                               vertices.push_back(vertex);
+                                               indices.push_back((deUint32)vertices.size() - 1);
+
+                                               primitiveStart = false;
+                                       }
+
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((deUint32)vertices.size() - 1);
+                               }
+                       }
+                       break;
+               }
+
+               case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (isRestartPrimitive(primitiveNdx))
+                               {
+                                       indices.push_back(0);
+                                       indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+                                       primitiveStart = true;
+                               }
+                               else
+                               {
+                                       if (primitiveStart)
+                                       {
+                                               indices.push_back(0);
+
+                                               const Vertex4RGBA vertex =
+                                               {
+                                                       tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                       red
+                                               };
+
+                                               vertices.push_back(vertex);
+                                               indices.push_back((deUint32)vertices.size() - 1);
+
+                                               primitiveStart = false;
+                                       }
+
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((deUint32)vertices.size() - 1);
+                               }
+                       }
+
+                       indices.push_back(0);
+                       break;
+
+               case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+                       vertices.push_back(defaultVertex);
+
+                       for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
+                       {
+                               if (isRestartPrimitive(primitiveNdx))
+                               {
+                                       indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
+                                       primitiveStart = true;
+                               }
+                               else
+                               {
+                                       if (primitiveStart)
+                                       {
+                                               for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
+                                               {
+                                                       const Vertex4RGBA vertex =
+                                                       {
+                                                               tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                                               red
+                                                       };
+
+                                                       vertices.push_back(vertex);
+                                                       indices.push_back((deUint32)vertices.size() - 1);
+                                                       indices.push_back(0);
+                                               }
+
+                                               primitiveStart = false;
+                                       }
+
+                                       const Vertex4RGBA vertex =
+                                       {
+                                               tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
+                                               red
+                                       };
+
+                                       vertices.push_back(vertex);
+                                       indices.push_back((deUint32)vertices.size() - 1);
+                                       indices.push_back(0);
+                               }
+                       }
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+                       break;
+       }
+
+       vertexData      = vertices;
+       indexData       = indices;
+}
+
+bool PrimitiveRestartTest::isRestartPrimitive (int primitiveIndex) const
+{
+       return std::find(m_restartPrimitives.begin(), m_restartPrimitives.end(), primitiveIndex) != m_restartPrimitives.end();
+}
+
+
+// InputAssemblyInstance
+
+InputAssemblyInstance::InputAssemblyInstance (Context&                                                 context,
+                                                                                         VkPrimitiveTopology                           primitiveTopology,
+                                                                                         bool                                                          testPrimitiveRestart,
+                                                                                         VkIndexType                                           indexType,
+                                                                                         const std::vector<deUint32>&          indexBufferData,
+                                                                                         const std::vector<Vertex4RGBA>&       vertexBufferData)
+
+       : vkt::TestInstance                     (context)
+       , m_primitiveTopology           (primitiveTopology)
+       , m_primitiveRestartEnable      (testPrimitiveRestart)
+       , m_indexType                           (indexType)
+       , m_vertices                            (vertexBufferData)
+       , m_indices                                     (indexBufferData)
+       , m_renderSize                          ((primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) ? tcu::IVec2(32, 32) : tcu::IVec2(64, 16))
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+{
+       const DeviceInterface&                  vk                                              = context.getDeviceInterface();
+       const VkDevice                                  vkDevice                                = context.getDevice();
+       const deUint32                                  queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                                 memAlloc                                (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+       const VkComponentMapping                componentMappingRGBA    = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+       // Create color image
+       {
+               const VkImageCreateInfo colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+                       m_colorFormat,                                                                                                                          // VkFormat                                     format;
+                       { m_renderSize.x(), m_renderSize.y(), 1u },                                                                     // VkExtent3D                           extent;
+                       1u,                                                                                                                                                     // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                     arrayLayers;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED                                                                                                       // VkImageLayout                        initialLayout;
+               };
+
+               m_colorImageCreateInfo  = colorImageParams;
+               m_colorImage                    = createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+               // Allocate and bind color image memory
+               m_colorImageAlloc               = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+       }
+
+       // Create color attachment view
+       {
+               const VkImageViewCreateInfo colorAttachmentViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,                       // VkStructureType                      sType;
+                       DE_NULL,                                                                                        // const void*                          pNext;
+                       0u,                                                                                                     // VkImageViewCreateFlags       flags;
+                       *m_colorImage,                                                                          // VkImage                                      image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                          // VkImageViewType                      viewType;
+                       m_colorFormat,                                                                          // VkFormat                                     format;
+                       componentMappingRGBA,                                                           // VkComponentMapping           components;
+                       { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },          // VkImageSubresourceRange      subresourceRange;
+               };
+
+               m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+       }
+
+       // Create render pass
+       {
+               const VkAttachmentDescription colorAttachmentDescription =
+               {
+                       0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
+                       m_colorFormat,                                                                          // 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 colorAttachmentReference =
+               {
+                       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;
+                       &colorAttachmentReference,                                                      // 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;
+                       &colorAttachmentDescription,                                            // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                      sType;
+                       DE_NULL,                                                                                        // const void*                          pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags     flags;
+                       *m_renderPass,                                                                          // VkRenderPass                         renderPass;
+                       1u,                                                                                                     // deUint32                                     attachmentCount;
+                       &m_colorAttachmentView.get(),                                           // const VkImageView*           pAttachments;
+                       (deUint32)m_renderSize.x(),                                                     // deUint32                                     width;
+                       (deUint32)m_renderSize.y(),                                                     // deUint32                                     height;
+                       1u                                                                                                      // deUint32                                     layers;
+               };
+
+               m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // const void*                                          pNext;
+                       0u,                                                                                                     // VkPipelineLayoutCreateFlags          flags;
+                       0u,                                                                                                     // deUint32                                                     setLayoutCount;
+                       DE_NULL,                                                                                        // const VkDescriptorSetLayout*         pSetLayouts;
+                       0u,                                                                                                     // deUint32                                                     pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*           pPushConstantRanges;
+               };
+
+               m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       m_vertexShaderModule    = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+       m_fragmentShaderModule  = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+       // Create pipeline
+       {
+               const VkPipelineShaderStageCreateInfo shaderStageParams[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;
+                               *m_vertexShaderModule,                                                                          // 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;
+                               *m_fragmentShaderModule,                                                                        // VkShaderModule                                               module;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       }
+               };
+
+               const VkVertexInputBindingDescription vertexInputBindingDescription =
+               {
+                       0u,                                                             // deUint32                                     binding;
+                       sizeof(Vertex4RGBA),                    // deUint32                                     stride;
+                       VK_VERTEX_INPUT_RATE_VERTEX             // VkVertexInputRate            inputRate;
+               };
+
+               const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
+               {
+                       {
+                               0u,                                                                     // deUint32     location;
+                               0u,                                                                     // deUint32     binding;
+                               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                               0u                                                                      // deUint32     offset;
+                       },
+                       {
+                               1u,                                                                     // deUint32     location;
+                               0u,                                                                     // deUint32     binding;
+                               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                               DE_OFFSET_OF(Vertex4RGBA, color),       // deUint32     offset;
+                       }
+               };
+
+               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;
+                       &vertexInputBindingDescription,                                                                 // const VkVertexInputBindingDescription*               pVertexBindingDescriptions;
+                       2u,                                                                                                                             // deUint32                                                                             vertexAttributeDescriptionCount;
+                       vertexInputAttributeDescriptions                                                                // 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;
+                       m_primitiveTopology,                                                                                    // VkPrimitiveTopology                                          topology;
+                       m_primitiveRestartEnable                                                                                // VkBool32                                                                     primitiveRestartEnable;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        x;
+                       0.0f,                                           // float        y;
+                       (float)m_renderSize.x(),        // float        width;
+                       (float)m_renderSize.y(),        // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+               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                                                             scissorCount;
+                       &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;
+                       VK_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,                                                                                    // VkBlendFactor                        srcColorBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                   // VkBlendFactor                        dstColorBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                // VkBlendOp                            colorBlendOp;
+                       VK_BLEND_FACTOR_ONE,                                                                                    // VkBlendFactor                        srcAlphaBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                   // VkBlendFactor                        dstAlphaBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                // VkBlendOp                            alphaBlendOp;
+                       VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                   // VkColorComponentFlags        colorWriteMask;
+                               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 VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                          // VkSampleCountFlagBits                                        rasterizationSamples;
+                       false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                           // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+                       false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+                       false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+               };
+
+               VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineDepthStencilStateCreateFlags       flags;
+                       false,                                                                                                          // VkBool32                                                                     depthTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     depthWriteEnable;
+                       VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                                                          depthCompareOp;
+                       false,                                                                                                          // VkBool32                                                                     depthBoundsTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     stencilTestEnable;
+                       // VkStencilOpState     front;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       // VkStencilOpState     back;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       -1.0f,                                                                                                          // float                        minDepthBounds;
+                       +1.0f                                                                                                           // float                        maxDepthBounds;
+               };
+
+               const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+               {
+                       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;
+                       shaderStageParams,                                                                      // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &depthStencilStateParams,                                                       // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateParams,                                                            // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *m_pipelineLayout,                                                                      // VkPipelineLayout                                                                     layout;
+                       *m_renderPass,                                                                          // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create vertex and index buffer
+       {
+               const VkBufferCreateInfo indexBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkBufferCreateFlags  flags;
+                       m_indices.size() * sizeof(deUint32),            // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_INDEX_BUFFER_BIT,                       // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                     // deUint32                             queueFamilyIndexCount;
+                       &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+
+               const VkBufferCreateInfo vertexBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkBufferCreateFlags  flags;
+                       m_vertices.size() * sizeof(Vertex4RGBA),        // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                      // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                     // deUint32                             queueFamilyIndexCount;
+                       &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+
+               m_indexBuffer           = createBuffer(vk, vkDevice, &indexBufferParams);
+               m_indexBufferAlloc      = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_indexBuffer), MemoryRequirement::HostVisible);
+
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_indexBuffer, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset()));
+
+               m_vertexBuffer          = createBuffer(vk, vkDevice, &vertexBufferParams);
+               m_vertexBufferAlloc     = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+               // Load vertices into index buffer
+               if (m_indexType == VK_INDEX_TYPE_UINT32)
+               {
+                       deMemcpy(m_indexBufferAlloc->getHostPtr(), m_indices.data(), m_indices.size() * sizeof(deUint32));
+               }
+               else // m_indexType == VK_INDEX_TYPE_UINT16
+               {
+                       uploadIndexBufferData16((deUint16*)m_indexBufferAlloc->getHostPtr(), m_indices);
+               }
+
+               // Load vertices into vertex buffer
+               deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+
+               // Flush memory
+               const VkMappedMemoryRange flushMemoryRanges[] =
+               {
+                       {
+                               VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  // VkStructureType      sType;
+                               DE_NULL,                                                                // const void*          pNext;
+                               m_indexBufferAlloc->getMemory(),                // VkDeviceMemory       memory;
+                               m_indexBufferAlloc->getOffset(),                // VkDeviceSize         offset;
+                               indexBufferParams.size                                  // VkDeviceSize         size;
+                       },
+                       {
+                               VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  // VkStructureType      sType;
+                               DE_NULL,                                                                // const void*          pNext;
+                               m_vertexBufferAlloc->getMemory(),               // VkDeviceMemory       memory;
+                               m_vertexBufferAlloc->getOffset(),               // VkDeviceSize         offset;
+                               vertexBufferParams.size                                 // VkDeviceSize         size;
+                       },
+               };
+
+               vk.flushMappedMemoryRanges(vkDevice, 2, flushMemoryRanges);
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,             // VkStructureType                              sType;
+                       DE_NULL,                                                                                // const void*                                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                   // VkCommandPoolCreateFlags             flags;
+                       queueFamilyIndex                                                                // deUint32                                             queueFamilyIndex;
+               };
+
+               m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *m_cmdPool,                                                                             // VkCommandPool                        commandPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCommandBufferLevel         level;
+                       1u                                                                                              // deUint32                                     bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCommandBufferUsageFlags            flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       false,                                                                                  // VkBool32                                                     occlusionQueryEnable;
+                       0u,                                                                                             // VkQueryControlFlags                          queryFlags;
+                       0u                                                                                              // VkQueryPipelineStatisticFlags        pipelineStatistics;
+               };
+
+               const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *m_renderPass,                                                                                  // VkRenderPass                 renderPass;
+                       *m_framebuffer,                                                                                 // VkFramebuffer                framebuffer;
+                       { { 0, 0 } , { m_renderSize.x(), m_renderSize.y() } },  // VkRect2D                             renderArea;
+                       1u,                                                                                                             // deUint32                             clearValueCount;
+                       &attachmentClearValue                                                                   // const VkClearValue*  pClearValues;
+               };
+
+               m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+               VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               const VkDeviceSize vertexBufferOffset = 0;
+
+               vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+               vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+               vk.cmdBindIndexBuffer(*m_cmdBuffer, *m_indexBuffer, 0, m_indexType);
+               vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indices.size(), 1, 0, 0, 0);
+
+               vk.cmdEndRenderPass(*m_cmdBuffer);
+               VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               m_fence = createFence(vk, vkDevice, &fenceParams);
+       }
+}
+
+InputAssemblyInstance::~InputAssemblyInstance (void)
+{
+}
+
+tcu::TestStatus InputAssemblyInstance::iterate (void)
+{
+       const DeviceInterface&          vk                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice        = m_context.getDevice();
+       const VkQueue                           queue           = m_context.getUniversalQueue();
+       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;
+               &m_cmdBuffer.get(),                             // const VkCommandBuffer*       pCommandBuffers;
+               0u,                                                             // deUint32                                     signalSemaphoreCount;
+               DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+       };
+
+       VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+       VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+       return verifyImage();
+}
+
+tcu::TestStatus InputAssemblyInstance::verifyImage (void)
+{
+       const tcu::TextureFormat        tcuColorFormat          = mapVkFormat(m_colorFormat);
+       const tcu::TextureFormat        tcuStencilFormat        = tcu::TextureFormat();
+       const ColorVertexShader         vertexShader;
+       const ColorFragmentShader       fragmentShader          (tcuColorFormat, tcuStencilFormat);
+       const rr::Program                       program                         (&vertexShader, &fragmentShader);
+       ReferenceRenderer                       refRenderer                     (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
+       bool                                            compareOk                       = false;
+
+       // Render reference image
+       {
+               const rr::PrimitiveType         topology        = mapVkPrimitiveTopology(m_primitiveTopology);
+               rr::RenderState                         renderState     (refRenderer.getViewportState());
+
+
+               if (m_primitiveRestartEnable)
+               {
+                       std::vector<deUint32> indicesRange;
+
+                       for (size_t indexNdx = 0; indexNdx < m_indices.size(); indexNdx++)
+                       {
+                               const bool isRestart = InputAssemblyTest::isRestartIndex(m_indexType, m_indices[indexNdx]);
+
+                               if (!isRestart)
+                                       indicesRange.push_back(m_indices[indexNdx]);
+
+                               if (isRestart || indexNdx == (m_indices.size() - 1))
+                               {
+                                       // Draw the range of indices found so far
+
+                                       std::vector<Vertex4RGBA> nonIndexedVertices;
+                                       for (size_t i = 0; i < indicesRange.size(); i++)
+                                               nonIndexedVertices.push_back(m_vertices[indicesRange[i]]);
+
+                                       refRenderer.draw(renderState, topology, nonIndexedVertices);
+                                       indicesRange.clear();
+                               }
+                       }
+               }
+               else
+               {
+                       std::vector<Vertex4RGBA> nonIndexedVertices;
+                       for (size_t i = 0; i < m_indices.size(); i++)
+                               nonIndexedVertices.push_back(m_vertices[m_indices[i]]);
+
+                       refRenderer.draw(renderState, topology, nonIndexedVertices);
+               }
+       }
+
+       // Compare result with reference image
+       {
+               const DeviceInterface&                          vk                                      = m_context.getDeviceInterface();
+               const VkDevice                                          vkDevice                        = m_context.getDevice();
+               const VkQueue                                           queue                           = m_context.getUniversalQueue();
+               const deUint32                                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+               SimpleAllocator                                         allocator                       (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+               de::UniquePtr<tcu::TextureLevel>        result                          (readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
+
+               compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+                                                                                                                         "IntImageCompare",
+                                                                                                                         "Image comparison",
+                                                                                                                         refRenderer.getAccess(),
+                                                                                                                         result->getAccess(),
+                                                                                                                         tcu::UVec4(2, 2, 2, 2),
+                                                                                                                         tcu::IVec3(1, 1, 0),
+                                                                                                                         true,
+                                                                                                                         tcu::COMPARE_LOG_RESULT);
+       }
+
+       if (compareOk)
+               return tcu::TestStatus::pass("Result image matches reference");
+       else
+               return tcu::TestStatus::fail("Image mismatch");
+}
+
+void InputAssemblyInstance::uploadIndexBufferData16    (deUint16* destPtr, const std::vector<deUint32>& indexBufferData)
+{
+       for (size_t i = 0; i < indexBufferData.size(); i++)
+       {
+               DE_ASSERT(indexBufferData[i] <= 0xFFFF);
+               destPtr[i] = (deUint16)indexBufferData[i];
+       }
+}
+
+
+// Utilities for test names
+
+std::string getPrimitiveTopologyCaseName (VkPrimitiveTopology topology)
+{
+       const std::string  fullName = getPrimitiveTopologyName(topology);
+
+       DE_ASSERT(de::beginsWith(fullName, "VK_PRIMITIVE_TOPOLOGY_"));
+
+       return de::toLower(fullName.substr(22));
+}
+
+de::MovePtr<tcu::TestCaseGroup> createPrimitiveTopologyTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> primitiveTopologyTests (new tcu::TestCaseGroup(testCtx, "primitive_topology", ""));
+
+       for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(InputAssemblyTest::s_primitiveTopologies); topologyNdx++)
+       {
+               const VkPrimitiveTopology topology = InputAssemblyTest::s_primitiveTopologies[topologyNdx];
+
+               primitiveTopologyTests->addChild(new PrimitiveTopologyTest(testCtx,
+                                                                                                                                  getPrimitiveTopologyCaseName(topology),
+                                                                                                                                  "",
+                                                                                                                                  topology));
+       }
+
+       return primitiveTopologyTests;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createPrimitiveRestartTests (tcu::TestContext& testCtx)
+{
+       const VkPrimitiveTopology primitiveRestartTopologies[] =
+       {
+               VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
+               VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
+               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
+       };
+
+       de::MovePtr<tcu::TestCaseGroup> primitiveRestartTests (new tcu::TestCaseGroup(testCtx, "primitive_restart", "Restarts indices of "));
+
+       de::MovePtr<tcu::TestCaseGroup> indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16", ""));
+       de::MovePtr<tcu::TestCaseGroup> indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32", ""));
+
+       for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(primitiveRestartTopologies); topologyNdx++)
+       {
+               const VkPrimitiveTopology topology = primitiveRestartTopologies[topologyNdx];
+
+               indexUint16Tests->addChild(new PrimitiveRestartTest(testCtx,
+                                                                                                                       getPrimitiveTopologyCaseName(topology),
+                                                                                                                       "",
+                                                                                                                       topology,
+                                                                                                                       VK_INDEX_TYPE_UINT16));
+
+               indexUint32Tests->addChild(new PrimitiveRestartTest(testCtx,
+                                                                                                                       getPrimitiveTopologyCaseName(topology),
+                                                                                                                       "",
+                                                                                                                       topology,
+                                                                                                                       VK_INDEX_TYPE_UINT32));
+       }
+
+       primitiveRestartTests->addChild(indexUint16Tests.release());
+       primitiveRestartTests->addChild(indexUint32Tests.release());
+
+       return primitiveRestartTests;
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup>         inputAssemblyTests (new tcu::TestCaseGroup(testCtx, "input_assembly", "Input assembly tests"));
+
+       inputAssemblyTests->addChild(createPrimitiveTopologyTests(testCtx).release());
+       inputAssemblyTests->addChild(createPrimitiveRestartTests(testCtx).release());
+
+       return inputAssemblyTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineInputAssemblyTests.hpp
new file mode 100644 (file)
index 0000000..894a31b
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
+#define _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Input Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEINPUTASSEMBLYTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.cpp
new file mode 100644 (file)
index 0000000..2320fc3
--- /dev/null
@@ -0,0 +1,2022 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Multisample Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineMultisampleTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deMemory.h"
+
+#include <sstream>
+#include <vector>
+#include <map>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+enum GeometryType
+{
+       GEOMETRY_TYPE_OPAQUE_TRIANGLE,
+       GEOMETRY_TYPE_OPAQUE_LINE,
+       GEOMETRY_TYPE_OPAQUE_POINT,
+       GEOMETRY_TYPE_OPAQUE_QUAD,
+       GEOMETRY_TYPE_TRANSLUCENT_QUAD,
+       GEOMETRY_TYPE_INVISIBLE_QUAD,
+       GEOMETRY_TYPE_GRADIENT_QUAD
+};
+
+
+bool                                                                   isSupportedSampleCount                          (const InstanceInterface& instanceInterface, VkPhysicalDevice physicalDevice, VkSampleCountFlagBits rasterizationSamples);
+VkPipelineColorBlendAttachmentState            getDefaultColorBlendAttachmentState     (void);
+deUint32                                                               getUniqueColorsCount                            (const tcu::ConstPixelBufferAccess& image);
+void                                                                   initMultisamplePrograms                         (SourceCollections& sources, GeometryType geometryType);
+
+class MultisampleTest : public vkt::TestCase
+{
+public:
+
+                                                                                               MultisampleTest                                         (tcu::TestContext&                                                              testContext,
+                                                                                                                                                                        const std::string&                                                             name,
+                                                                                                                                                                        const std::string&                                                             description,
+                                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState,
+                                                                                                                                                                        GeometryType                                                                   geometryType);
+       virtual                                                                         ~MultisampleTest                                        (void);
+
+       virtual void                                                            initPrograms                                            (SourceCollections& programCollection) const;
+       virtual TestInstance*                                           createInstance                                          (Context& context) const;
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance           (Context&                                                                               context,
+                                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const = 0;
+       VkPipelineMultisampleStateCreateInfo            m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+       const GeometryType                                                      m_geometryType;
+       std::vector<VkSampleMask>                                       m_sampleMask;
+};
+
+class RasterizationSamplesTest : public MultisampleTest
+{
+public:
+                                                                                               RasterizationSamplesTest                        (tcu::TestContext&              testContext,
+                                                                                                                                                                        const std::string&             name,
+                                                                                                                                                                        const std::string&             description,
+                                                                                                                                                                        VkSampleCountFlagBits  rasterizationSamples,
+                                                                                                                                                                        GeometryType                   geometryType);
+       virtual                                                                         ~RasterizationSamplesTest                       (void) {}
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance           (Context&                                                                               context,
+                                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const;
+
+       static VkPipelineMultisampleStateCreateInfo     getRasterizationSamplesStateParams      (VkSampleCountFlagBits rasterizationSamples);
+};
+
+class MinSampleShadingTest : public MultisampleTest
+{
+public:
+                                                                                               MinSampleShadingTest                            (tcu::TestContext&              testContext,
+                                                                                                                                                                        const std::string&             name,
+                                                                                                                                                                        const std::string&             description,
+                                                                                                                                                                        VkSampleCountFlagBits  rasterizationSamples,
+                                                                                                                                                                        float                                  minSampleShading,
+                                                                                                                                                                        GeometryType                   geometryType);
+       virtual                                                                         ~MinSampleShadingTest                           (void) {}
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance           (Context&                                                                               context,
+                                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const;
+
+       static VkPipelineMultisampleStateCreateInfo     getMinSampleShadingStateParams          (VkSampleCountFlagBits rasterizationSamples, float minSampleShading);
+};
+
+class SampleMaskTest : public MultisampleTest
+{
+public:
+                                                                                               SampleMaskTest                                          (tcu::TestContext&                                      testContext,
+                                                                                                                                                                        const std::string&                                     name,
+                                                                                                                                                                        const std::string&                                     description,
+                                                                                                                                                                        VkSampleCountFlagBits                          rasterizationSamples,
+                                                                                                                                                                        const std::vector<VkSampleMask>&       sampleMask,
+                                                                                                                                                                        GeometryType                                           geometryType);
+
+       virtual                                                                         ~SampleMaskTest                                         (void) {}
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance           (Context&                                                                               context,
+                                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const;
+
+       static VkPipelineMultisampleStateCreateInfo     getSampleMaskStateParams                        (VkSampleCountFlagBits rasterizationSamples, const std::vector<VkSampleMask>& sampleMask);
+};
+
+class AlphaToOneTest : public MultisampleTest
+{
+public:
+                                                                                               AlphaToOneTest                                  (tcu::TestContext&                                      testContext,
+                                                                                                                                                                const std::string&                                     name,
+                                                                                                                                                                const std::string&                                     description,
+                                                                                                                                                                VkSampleCountFlagBits                          rasterizationSamples);
+
+       virtual                                                                         ~AlphaToOneTest                                 (void) {}
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance   (Context&                                                                               context,
+                                                                                                                                                                VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                const VkPipelineColorBlendAttachmentState&             colorBlendState) const;
+
+       static VkPipelineMultisampleStateCreateInfo     getAlphaToOneStateParams                (VkSampleCountFlagBits rasterizationSamples);
+       static VkPipelineColorBlendAttachmentState      getAlphaToOneBlendState                 (void);
+};
+
+class AlphaToCoverageTest : public MultisampleTest
+{
+public:
+                                                                                               AlphaToCoverageTest                             (tcu::TestContext&              testContext,
+                                                                                                                                                                const std::string&             name,
+                                                                                                                                                                const std::string&             description,
+                                                                                                                                                                VkSampleCountFlagBits  rasterizationSamples,
+                                                                                                                                                                GeometryType                   geometryType);
+
+       virtual                                                                         ~AlphaToCoverageTest                    (void) {}
+
+protected:
+       virtual TestInstance*                                           createMultisampleTestInstance   (Context&                                                                               context,
+                                                                                                                                                                VkPrimitiveTopology                                                    topology,
+                                                                                                                                                                const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                                const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                                const VkPipelineColorBlendAttachmentState&             colorBlendState) const;
+
+       static VkPipelineMultisampleStateCreateInfo     getAlphaToCoverageStateParams   (VkSampleCountFlagBits rasterizationSamples);
+
+       GeometryType                                                            m_geometryType;
+};
+
+class MultisampleRenderer
+{
+public:
+                                                                                               MultisampleRenderer                     (Context&                                                                               context,
+                                                                                                                                                        VkFormat                                                                               colorFormat,
+                                                                                                                                                        const tcu::IVec2&                                                              renderSize,
+                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState);
+
+       virtual                                                                         ~MultisampleRenderer            (void);
+
+       de::MovePtr<tcu::TextureLevel>                          render                                          (void);
+
+protected:
+       Context&                                                                        m_context;
+
+       const VkFormat                                                          m_colorFormat;
+       tcu::IVec2                                                                      m_renderSize;
+
+       const VkPipelineMultisampleStateCreateInfo      m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+
+       Move<VkImage>                                                           m_colorImage;
+       de::MovePtr<Allocation>                                         m_colorImageAlloc;
+       Move<VkImageView>                                                       m_colorAttachmentView;
+
+       Move<VkImage>                                                           m_resolveImage;
+       de::MovePtr<Allocation>                                         m_resolveImageAlloc;
+       Move<VkImageView>                                                       m_resolveAttachmentView;
+
+       Move<VkRenderPass>                                                      m_renderPass;
+       Move<VkFramebuffer>                                                     m_framebuffer;
+
+       Move<VkShaderModule>                                            m_vertexShaderModule;
+       Move<VkShaderModule>                                            m_fragmentShaderModule;
+
+       Move<VkBuffer>                                                          m_vertexBuffer;
+       de::MovePtr<Allocation>                                         m_vertexBufferAlloc;
+
+       Move<VkPipelineLayout>                                          m_pipelineLayout;
+       Move<VkPipeline>                                                        m_graphicsPipeline;
+
+       Move<VkCommandPool>                                                     m_cmdPool;
+       Move<VkCommandBuffer>                                           m_cmdBuffer;
+
+       Move<VkFence>                                                           m_fence;
+};
+
+class RasterizationSamplesInstance : public vkt::TestInstance
+{
+public:
+                                                                       RasterizationSamplesInstance    (Context&                                                                               context,
+                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState);
+       virtual                                                 ~RasterizationSamplesInstance   (void) {}
+
+       virtual tcu::TestStatus                 iterate                                                 (void);
+
+protected:
+       virtual tcu::TestStatus                 verifyImage                                             (const tcu::ConstPixelBufferAccess& result);
+
+       const VkFormat                                  m_colorFormat;
+       const tcu::IVec2                                m_renderSize;
+       const VkPrimitiveTopology               m_primitiveTopology;
+       const std::vector<Vertex4RGBA>  m_vertices;
+       MultisampleRenderer                             m_multisampleRenderer;
+};
+
+class MinSampleShadingInstance : public vkt::TestInstance
+{
+public:
+                                                                                               MinSampleShadingInstance        (Context&                                                                               context,
+                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState);
+       virtual                                                                         ~MinSampleShadingInstance       (void) {}
+
+       virtual tcu::TestStatus                                         iterate                                         (void);
+
+protected:
+       virtual tcu::TestStatus                                         verifyImage                                     (const tcu::ConstPixelBufferAccess& testShadingImage,
+                                                                                                                                                        const tcu::ConstPixelBufferAccess& minShadingImage,
+                                                                                                                                                        const tcu::ConstPixelBufferAccess& maxShadingImage);
+       const VkFormat                                                          m_colorFormat;
+       const tcu::IVec2                                                        m_renderSize;
+       const VkPrimitiveTopology                                       m_primitiveTopology;
+       const std::vector<Vertex4RGBA>                          m_vertices;
+       const VkPipelineMultisampleStateCreateInfo      m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+};
+
+class SampleMaskInstance : public vkt::TestInstance
+{
+public:
+                                                                                               SampleMaskInstance                      (Context&                                                                               context,
+                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState);
+       virtual                                                                         ~SampleMaskInstance                     (void) {}
+
+       virtual tcu::TestStatus                                         iterate                                         (void);
+
+protected:
+       virtual tcu::TestStatus                                         verifyImage                                     (const tcu::ConstPixelBufferAccess& testShadingImage,
+                                                                                                                                                        const tcu::ConstPixelBufferAccess& minShadingImage,
+                                                                                                                                                        const tcu::ConstPixelBufferAccess& maxShadingImage);
+       const VkFormat                                                          m_colorFormat;
+       const tcu::IVec2                                                        m_renderSize;
+       const VkPrimitiveTopology                                       m_primitiveTopology;
+       const std::vector<Vertex4RGBA>                          m_vertices;
+       const VkPipelineMultisampleStateCreateInfo      m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+};
+
+class AlphaToOneInstance : public vkt::TestInstance
+{
+public:
+                                                                                               AlphaToOneInstance                      (Context&                                                                               context,
+                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState);
+       virtual                                                                         ~AlphaToOneInstance                     (void) {}
+
+       virtual tcu::TestStatus                                         iterate                                         (void);
+
+protected:
+       virtual tcu::TestStatus                                         verifyImage                                     (const tcu::ConstPixelBufferAccess& alphaOneImage,
+                                                                                                                                                        const tcu::ConstPixelBufferAccess& noAlphaOneImage);
+       const VkFormat                                                          m_colorFormat;
+       const tcu::IVec2                                                        m_renderSize;
+       const VkPrimitiveTopology                                       m_primitiveTopology;
+       const std::vector<Vertex4RGBA>                          m_vertices;
+       const VkPipelineMultisampleStateCreateInfo      m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+};
+
+class AlphaToCoverageInstance : public vkt::TestInstance
+{
+public:
+                                                                                               AlphaToCoverageInstance         (Context&                                                                               context,
+                                                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                                                        const VkPipelineColorBlendAttachmentState&             blendState,
+                                                                                                                                                        GeometryType                                                                   geometryType);
+       virtual                                                                         ~AlphaToCoverageInstance        (void) {}
+
+       virtual tcu::TestStatus                                         iterate                                         (void);
+
+protected:
+       virtual tcu::TestStatus                                         verifyImage                                     (const tcu::ConstPixelBufferAccess& result);
+       const VkFormat                                                          m_colorFormat;
+       const tcu::IVec2                                                        m_renderSize;
+       const VkPrimitiveTopology                                       m_primitiveTopology;
+       const std::vector<Vertex4RGBA>                          m_vertices;
+       const VkPipelineMultisampleStateCreateInfo      m_multisampleStateParams;
+       const VkPipelineColorBlendAttachmentState       m_colorBlendState;
+       const GeometryType                      m_geometryType;
+};
+
+
+// Helper functions
+
+void initMultisamplePrograms (SourceCollections& sources, GeometryType geometryType)
+{
+       std::ostringstream vertexSource;
+
+       vertexSource <<
+               "#version 310 es\n"
+               "layout(location = 0) in vec4 position;\n"
+               "layout(location = 1) in vec4 color;\n"
+               "layout(location = 0) out highp vec4 vtxColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "       gl_Position = position;\n"
+               "       vtxColor = color;\n"
+               << (geometryType == GEOMETRY_TYPE_OPAQUE_POINT ? "      gl_PointSize = 3.0f;\n"
+                                                                                                                : "" )
+               << "}\n";
+
+       static const char* fragmentSource =
+               "#version 310 es\n"
+               "layout(location = 0) in highp vec4 vtxColor;\n"
+               "layout(location = 0) out highp vec4 fragColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "       fragColor = vtxColor;\n"
+               "}\n";
+
+       sources.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
+       sources.glslSources.add("color_frag") << glu::FragmentSource(fragmentSource);
+}
+
+bool isSupportedSampleCount (const InstanceInterface& instanceInterface, VkPhysicalDevice physicalDevice, VkSampleCountFlagBits rasterizationSamples)
+{
+       VkPhysicalDeviceProperties deviceProperties;
+
+       instanceInterface.getPhysicalDeviceProperties(physicalDevice, &deviceProperties);
+
+       return !!(deviceProperties.limits.framebufferColorSampleCounts & rasterizationSamples);
+}
+
+VkPipelineColorBlendAttachmentState getDefaultColorBlendAttachmentState (void)
+{
+       const VkPipelineColorBlendAttachmentState colorBlendState =
+       {
+               false,                                                                                                          // VkBool32                                     blendEnable;
+               VK_BLEND_FACTOR_ONE,                                                                            // VkBlendFactor                        srcColorBlendFactor;
+               VK_BLEND_FACTOR_ZERO,                                                                           // VkBlendFactor                        dstColorBlendFactor;
+               VK_BLEND_OP_ADD,                                                                                        // VkBlendOp                            colorBlendOp;
+               VK_BLEND_FACTOR_ONE,                                                                            // VkBlendFactor                        srcAlphaBlendFactor;
+               VK_BLEND_FACTOR_ZERO,                                                                           // VkBlendFactor                        dstAlphaBlendFactor;
+               VK_BLEND_OP_ADD,                                                                                        // VkBlendOp                            alphaBlendOp;
+               VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |           // VkColorComponentFlags        colorWriteMask;
+                       VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+       };
+
+       return colorBlendState;
+}
+
+deUint32 getUniqueColorsCount (const tcu::ConstPixelBufferAccess& image)
+{
+       DE_ASSERT(image.getFormat().getPixelSize() == 4);
+
+       std::map<deUint32, deUint32>    histogram; // map<pixel value, number of occurrences>
+       const deUint32                                  pixelCount      = image.getWidth() * image.getHeight() * image.getDepth();
+
+       for (deUint32 pixelNdx = 0; pixelNdx < pixelCount; pixelNdx++)
+       {
+               const deUint32 pixelValue = *((const deUint32*)image.getDataPtr() + pixelNdx);
+
+               if (histogram.find(pixelValue) != histogram.end())
+                       histogram[pixelValue]++;
+               else
+                       histogram[pixelValue] = 1;
+       }
+
+       return (deUint32)histogram.size();
+}
+
+
+// MultisampleTest
+
+MultisampleTest::MultisampleTest (tcu::TestContext&                                                            testContext,
+                                                                 const std::string&                                                    name,
+                                                                 const std::string&                                                    description,
+                                                                 const VkPipelineMultisampleStateCreateInfo&   multisampleStateParams,
+                                                                 const VkPipelineColorBlendAttachmentState&    blendState,
+                                                                 GeometryType                                                                  geometryType)
+       : vkt::TestCase                         (testContext, name, description)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (blendState)
+       , m_geometryType                        (geometryType)
+{
+       if (m_multisampleStateParams.pSampleMask)
+       {
+               // Copy pSampleMask to avoid dependencies with other classes
+
+               const deUint32 maskCount = m_multisampleStateParams.rasterizationSamples / 32;
+
+               for (deUint32 maskNdx = 0; maskNdx < maskCount; maskNdx++)
+                       m_sampleMask.push_back(m_multisampleStateParams.pSampleMask[maskNdx]);
+
+               m_multisampleStateParams.pSampleMask = m_sampleMask.data();
+       }
+}
+
+MultisampleTest::~MultisampleTest (void)
+{
+}
+
+void MultisampleTest::initPrograms (SourceCollections& programCollection) const
+{
+       initMultisamplePrograms(programCollection, m_geometryType);
+}
+
+TestInstance* MultisampleTest::createInstance (Context& context) const
+{
+       VkPrimitiveTopology                     topology;
+       std::vector<Vertex4RGBA>        vertices;
+
+       switch (m_geometryType)
+       {
+               case GEOMETRY_TYPE_OPAQUE_TRIANGLE:
+               {
+                       topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+                       const Vertex4RGBA vertexData[3] =
+                       {
+                               {
+                                       tcu::Vec4(-0.75f, 0.0f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(0.75f, 0.125f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(0.75f, -0.125f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               }
+                       };
+
+                       vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 3);
+                       break;
+               }
+
+               case GEOMETRY_TYPE_OPAQUE_LINE:
+               {
+                       topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+
+                       const Vertex4RGBA vertexData[2] =
+                       {
+                               {
+                                       tcu::Vec4(-0.75f, 0.25f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(0.75f, -0.25f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               }
+                       };
+
+                       vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 2);
+                       break;
+               }
+
+               case GEOMETRY_TYPE_OPAQUE_POINT:
+               {
+                       topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+
+                       const Vertex4RGBA vertex =
+                       {
+                               tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
+                               tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                       };
+
+                       vertices = std::vector<Vertex4RGBA>(1, vertex);
+                       break;
+               }
+
+               case GEOMETRY_TYPE_OPAQUE_QUAD:
+               case GEOMETRY_TYPE_TRANSLUCENT_QUAD:
+               case GEOMETRY_TYPE_INVISIBLE_QUAD:
+               case GEOMETRY_TYPE_GRADIENT_QUAD:
+               {
+                       topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+
+                       Vertex4RGBA vertexData[4] =
+                       {
+                               {
+                                       tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               },
+                               {
+                                       tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
+                                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+                               }
+                       };
+
+                       if (m_geometryType == GEOMETRY_TYPE_TRANSLUCENT_QUAD)
+                       {
+                               for (int i = 0; i < 4; i++)
+                                       vertexData[i].color.w() = 0.25f;
+                       }
+                       else if (m_geometryType == GEOMETRY_TYPE_INVISIBLE_QUAD)
+                       {
+                               for (int i = 0; i < 4; i++)
+                                       vertexData[i].color.w() = 0.0f;
+                       }
+                       else if (m_geometryType == GEOMETRY_TYPE_GRADIENT_QUAD)
+                       {
+                               vertexData[0].color.w() = 0.0f;
+                               vertexData[2].color.w() = 0.0f;
+                       }
+
+                       vertices = std::vector<Vertex4RGBA>(vertexData, vertexData + 4);
+                       break;
+               }
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       return createMultisampleTestInstance(context, topology, vertices, m_multisampleStateParams, m_colorBlendState);
+}
+
+
+// RasterizationSamplesTest
+
+RasterizationSamplesTest::RasterizationSamplesTest (tcu::TestContext&          testContext,
+                                                                                                       const std::string&              name,
+                                                                                                       const std::string&              description,
+                                                                                                       VkSampleCountFlagBits   rasterizationSamples,
+                                                                                                       GeometryType                    geometryType)
+       : MultisampleTest       (testContext, name, description, getRasterizationSamplesStateParams(rasterizationSamples), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+VkPipelineMultisampleStateCreateInfo RasterizationSamplesTest::getRasterizationSamplesStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+       const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+               rasterizationSamples,                                                                           // VkSampleCountFlagBits                                        rasterizationSamples;
+               false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+               0.0f,                                                                                                           // float                                                                        minSampleShading;
+               DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+               false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+               false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+       };
+
+       return multisampleStateParams;
+}
+
+TestInstance* RasterizationSamplesTest::createMultisampleTestInstance (Context&                                                                                context,
+                                                                                                                                          VkPrimitiveTopology                                                  topology,
+                                                                                                                                          const std::vector<Vertex4RGBA>&                              vertices,
+                                                                                                                                          const VkPipelineMultisampleStateCreateInfo&  multisampleStateParams,
+                                                                                                                                          const VkPipelineColorBlendAttachmentState&   colorBlendState) const
+{
+       return new RasterizationSamplesInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+
+// MinSampleShadingTest
+
+MinSampleShadingTest::MinSampleShadingTest (tcu::TestContext&          testContext,
+                                                                                       const std::string&              name,
+                                                                                       const std::string&              description,
+                                                                                       VkSampleCountFlagBits   rasterizationSamples,
+                                                                                       float                                   minSampleShading,
+                                                                                       GeometryType                    geometryType)
+       : MultisampleTest       (testContext, name, description, getMinSampleShadingStateParams(rasterizationSamples, minSampleShading), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+TestInstance* MinSampleShadingTest::createMultisampleTestInstance (Context&                                                                            context,
+                                                                                                                                  VkPrimitiveTopology                                                  topology,
+                                                                                                                                  const std::vector<Vertex4RGBA>&                              vertices,
+                                                                                                                                  const VkPipelineMultisampleStateCreateInfo&  multisampleStateParams,
+                                                                                                                                  const VkPipelineColorBlendAttachmentState&   colorBlendState) const
+{
+       return new MinSampleShadingInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo MinSampleShadingTest::getMinSampleShadingStateParams (VkSampleCountFlagBits rasterizationSamples, float minSampleShading)
+{
+       const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+               rasterizationSamples,                                                                           // VkSampleCountFlagBits                                        rasterizationSamples;
+               true,                                                                                                           // VkBool32                                                                     sampleShadingEnable;
+               minSampleShading,                                                                                       // float                                                                        minSampleShading;
+               DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+               false,                                                                                                          //  VkBool32                                                            alphaToCoverageEnable;
+               false                                                                                                           //  VkBool32                                                            alphaToOneEnable;
+       };
+
+       return multisampleStateParams;
+}
+
+
+// SampleMaskTest
+
+SampleMaskTest::SampleMaskTest (tcu::TestContext&                                      testContext,
+                                                               const std::string&                                      name,
+                                                               const std::string&                                      description,
+                                                               VkSampleCountFlagBits                           rasterizationSamples,
+                                                               const std::vector<VkSampleMask>&        sampleMask,
+                                                               GeometryType                                            geometryType)
+       : MultisampleTest       (testContext, name, description, getSampleMaskStateParams(rasterizationSamples, sampleMask), getDefaultColorBlendAttachmentState(), geometryType)
+{
+}
+
+TestInstance* SampleMaskTest::createMultisampleTestInstance (Context&                                                                          context,
+                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const
+{
+       return new SampleMaskInstance(context, topology,vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo SampleMaskTest::getSampleMaskStateParams (VkSampleCountFlagBits rasterizationSamples, const std::vector<VkSampleMask>& sampleMask)
+{
+       const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+               rasterizationSamples,                                                                           // VkSampleCountFlagBits                                        rasterizationSamples;
+               false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+               0.0f,                                                                                                           // float                                                                        minSampleShading;
+               sampleMask.data(),                                                                                      // const VkSampleMask*                                          pSampleMask;
+               false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+               false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+       };
+
+       return multisampleStateParams;
+}
+
+
+// AlphaToOneTest
+
+AlphaToOneTest::AlphaToOneTest (tcu::TestContext&              testContext,
+                                                               const std::string&              name,
+                                                               const std::string&              description,
+                                                               VkSampleCountFlagBits   rasterizationSamples)
+       : MultisampleTest       (testContext, name, description, getAlphaToOneStateParams(rasterizationSamples), getAlphaToOneBlendState(), GEOMETRY_TYPE_GRADIENT_QUAD)
+{
+}
+
+TestInstance* AlphaToOneTest::createMultisampleTestInstance (Context&                                                                          context,
+                                                                                                                        VkPrimitiveTopology                                                    topology,
+                                                                                                                        const std::vector<Vertex4RGBA>&                                vertices,
+                                                                                                                        const VkPipelineMultisampleStateCreateInfo&    multisampleStateParams,
+                                                                                                                        const VkPipelineColorBlendAttachmentState&             colorBlendState) const
+{
+       return new AlphaToOneInstance(context, topology, vertices, multisampleStateParams, colorBlendState);
+}
+
+VkPipelineMultisampleStateCreateInfo AlphaToOneTest::getAlphaToOneStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+       const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+               rasterizationSamples,                                                                           // VkSampleCountFlagBits                                        rasterizationSamples;
+               false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+               0.0f,                                                                                                           // float                                                                        minSampleShading;
+               DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+               false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+               true                                                                                                            // VkBool32                                                                     alphaToOneEnable;
+       };
+
+       return multisampleStateParams;
+}
+
+VkPipelineColorBlendAttachmentState AlphaToOneTest::getAlphaToOneBlendState (void)
+{
+       const VkPipelineColorBlendAttachmentState colorBlendState =
+       {
+               true,                                                                                                           // VkBool32                                     blendEnable;
+               VK_BLEND_FACTOR_SRC_ALPHA,                                                                      // VkBlendFactor                        srcColorBlendFactor;
+               VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,                                            // VkBlendFactor                        dstColorBlendFactor;
+               VK_BLEND_OP_ADD,                                                                                        // VkBlendOp                            colorBlendOp;
+               VK_BLEND_FACTOR_SRC_ALPHA,                                                                      // VkBlendFactor                        srcAlphaBlendFactor;
+               VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,                                            // VkBlendFactor                        dstAlphaBlendFactor;
+               VK_BLEND_OP_ADD,                                                                                        // VkBlendOp                            alphaBlendOp;
+               VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |           // VkColorComponentFlags        colorWriteMask;
+                       VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+       };
+
+       return colorBlendState;
+}
+
+
+// AlphaToCoverageTest
+
+AlphaToCoverageTest::AlphaToCoverageTest (tcu::TestContext&                    testContext,
+                                                                                 const std::string&            name,
+                                                                                 const std::string&            description,
+                                                                                 VkSampleCountFlagBits         rasterizationSamples,
+                                                                                 GeometryType                          geometryType)
+       : MultisampleTest       (testContext, name, description, getAlphaToCoverageStateParams(rasterizationSamples), getDefaultColorBlendAttachmentState(), geometryType)
+       , m_geometryType        (geometryType)
+{
+}
+
+TestInstance* AlphaToCoverageTest::createMultisampleTestInstance (Context&                                                                             context,
+                                                                                                                                 VkPrimitiveTopology                                                   topology,
+                                                                                                                                 const std::vector<Vertex4RGBA>&                               vertices,
+                                                                                                                                 const VkPipelineMultisampleStateCreateInfo&   multisampleStateParams,
+                                                                                                                                 const VkPipelineColorBlendAttachmentState&    colorBlendState) const
+{
+       return new AlphaToCoverageInstance(context, topology, vertices, multisampleStateParams, colorBlendState, m_geometryType);
+}
+
+VkPipelineMultisampleStateCreateInfo AlphaToCoverageTest::getAlphaToCoverageStateParams (VkSampleCountFlagBits rasterizationSamples)
+{
+       const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+               DE_NULL,                                                                                                        // const void*                                                          pNext;
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+               rasterizationSamples,                                                                           // VkSampleCountFlagBits                                        rasterizationSamples;
+               false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+               0.0f,                                                                                                           // float                                                                        minSampleShading;
+               DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+               true,                                                                                                           // VkBool32                                                                     alphaToCoverageEnable;
+               false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+       };
+
+       return multisampleStateParams;
+}
+
+// RasterizationSamplesInstance
+
+RasterizationSamplesInstance::RasterizationSamplesInstance (Context&                                                                           context,
+                                                                                                                       VkPrimitiveTopology                                                             topology,
+                                                                                                                       const std::vector<Vertex4RGBA>&                                 vertices,
+                                                                                                                       const VkPipelineMultisampleStateCreateInfo&             multisampleStateParams,
+                                                                                                                       const VkPipelineColorBlendAttachmentState&              blendState)
+       : vkt::TestInstance             (context)
+       , m_colorFormat                 (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_renderSize                  (32, 32)
+       , m_primitiveTopology   (topology)
+       , m_vertices                    (vertices)
+       , m_multisampleRenderer (context, m_colorFormat, m_renderSize, topology, vertices, multisampleStateParams, blendState)
+{
+}
+
+tcu::TestStatus RasterizationSamplesInstance::iterate (void)
+{
+       de::MovePtr<tcu::TextureLevel> level(m_multisampleRenderer.render());
+       return verifyImage(level->getAccess());
+}
+
+tcu::TestStatus RasterizationSamplesInstance::verifyImage (const tcu::ConstPixelBufferAccess& result)
+{
+       // Verify range of unique pixels
+       {
+               const deUint32  numUniqueColors = getUniqueColorsCount(result);
+               const deUint32  minUniqueColors = 3;
+
+               tcu::TestLog& log = m_context.getTestContext().getLog();
+
+               log << tcu::TestLog::Message
+                       << "\nMin. unique colors expected: " << minUniqueColors << "\n"
+                       << "Unique colors found: " << numUniqueColors << "\n"
+                       << tcu::TestLog::EndMessage;
+
+               if (numUniqueColors < minUniqueColors)
+                       return tcu::TestStatus::fail("Unique colors out of expected bounds");
+       }
+
+       // Verify shape of the rendered primitive (fuzzy-compare)
+       {
+               const tcu::TextureFormat        tcuColorFormat  = mapVkFormat(m_colorFormat);
+               const tcu::TextureFormat        tcuDepthFormat  = tcu::TextureFormat();
+               const ColorVertexShader         vertexShader;
+               const ColorFragmentShader       fragmentShader  (tcuColorFormat, tcuDepthFormat);
+               const rr::Program                       program                 (&vertexShader, &fragmentShader);
+               ReferenceRenderer                       refRenderer             (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+               rr::RenderState                         renderState             (refRenderer.getViewportState());
+
+               if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
+               {
+                       VkPhysicalDeviceProperties deviceProperties;
+
+                       m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &deviceProperties);
+
+                       // gl_PointSize is clamped to pointSizeRange
+                       renderState.point.pointSize = deFloatMin(3.0f, deviceProperties.limits.pointSizeRange[1]);
+               }
+
+               refRenderer.colorClear(tcu::Vec4(0.0f));
+               refRenderer.draw(renderState, mapVkPrimitiveTopology(m_primitiveTopology), m_vertices);
+
+               if (!tcu::fuzzyCompare(m_context.getTestContext().getLog(), "FuzzyImageCompare", "Image comparison", refRenderer.getAccess(), result, 0.05f, tcu::COMPARE_LOG_RESULT))
+                       return tcu::TestStatus::fail("Primitive has unexpected shape");
+
+       }
+
+       return tcu::TestStatus::pass("Primitive rendered, unique colors within expected bounds");
+}
+
+
+// MinSampleShadingInstance
+
+MinSampleShadingInstance::MinSampleShadingInstance (Context&                                                                   context,
+                                                                                                       VkPrimitiveTopology                                                     topology,
+                                                                                                       const std::vector<Vertex4RGBA>&                         vertices,
+                                                                                                       const VkPipelineMultisampleStateCreateInfo&     multisampleStateParams,
+                                                                                                       const VkPipelineColorBlendAttachmentState&      colorBlendState)
+       : vkt::TestInstance                     (context)
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_renderSize                          (32, 32)
+       , m_primitiveTopology           (topology)
+       , m_vertices                            (vertices)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (colorBlendState)
+{
+       VkPhysicalDeviceFeatures deviceFeatures;
+
+       m_context.getInstanceInterface().getPhysicalDeviceFeatures(m_context.getPhysicalDevice(), &deviceFeatures);
+
+       if (!deviceFeatures.sampleRateShading)
+               throw tcu::NotSupportedError("Sample shading is not supported");
+}
+
+tcu::TestStatus MinSampleShadingInstance::iterate (void)
+{
+       de::MovePtr<tcu::TextureLevel>                          testShadingImage;
+       de::MovePtr<tcu::TextureLevel>                          minShadingImage;
+       de::MovePtr<tcu::TextureLevel>                          maxShadingImage;
+
+       // Render with test minSampleShading
+       {
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+               testShadingImage = renderer.render();
+       }
+
+       // Render with minSampleShading = 0.0f
+       {
+               VkPipelineMultisampleStateCreateInfo    multisampleParams       = m_multisampleStateParams;
+               multisampleParams.minSampleShading = 0.0f;
+
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+               minShadingImage = renderer.render();
+       }
+
+       // Render with minSampleShading = 1.0f
+       {
+               VkPipelineMultisampleStateCreateInfo    multisampleParams       = m_multisampleStateParams;
+               multisampleParams.minSampleShading = 1.0f;
+
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+               maxShadingImage = renderer.render();
+       }
+
+       return verifyImage(testShadingImage->getAccess(), minShadingImage->getAccess(), maxShadingImage->getAccess());
+}
+
+tcu::TestStatus MinSampleShadingInstance::verifyImage (const tcu::ConstPixelBufferAccess& testShadingImage, const tcu::ConstPixelBufferAccess& minShadingImage, const tcu::ConstPixelBufferAccess& maxShadingImage)
+{
+       const deUint32  testColorCount  = getUniqueColorsCount(testShadingImage);
+       const deUint32  minColorCount   = getUniqueColorsCount(minShadingImage);
+       const deUint32  maxColorCount   = getUniqueColorsCount(maxShadingImage);
+
+       tcu::TestLog& log = m_context.getTestContext().getLog();
+
+       log << tcu::TestLog::Message
+               << "\nColors found: " << testColorCount << "\n"
+               << "Min. colors expected: " << minColorCount << "\n"
+               << "Max. colors expected: " << maxColorCount << "\n"
+               << tcu::TestLog::EndMessage;
+
+       if (minColorCount > testColorCount || testColorCount > maxColorCount)
+               return tcu::TestStatus::fail("Unique colors out of expected bounds");
+       else
+               return tcu::TestStatus::pass("Unique colors within expected bounds");
+}
+
+SampleMaskInstance::SampleMaskInstance (Context&                                                                               context,
+                                                                               VkPrimitiveTopology                                                             topology,
+                                                                               const std::vector<Vertex4RGBA>&                                 vertices,
+                                                                               const VkPipelineMultisampleStateCreateInfo&             multisampleStateParams,
+                                                                               const VkPipelineColorBlendAttachmentState&              blendState)
+       : vkt::TestInstance                     (context)
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_renderSize                          (32, 32)
+       , m_primitiveTopology           (topology)
+       , m_vertices                            (vertices)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (blendState)
+{
+}
+
+tcu::TestStatus SampleMaskInstance::iterate (void)
+{
+       de::MovePtr<tcu::TextureLevel>                          testSampleMaskImage;
+       de::MovePtr<tcu::TextureLevel>                          minSampleMaskImage;
+       de::MovePtr<tcu::TextureLevel>                          maxSampleMaskImage;
+
+       // Render with test flags
+       {
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+               testSampleMaskImage = renderer.render();
+       }
+
+       // Render with all flags off
+       {
+               VkPipelineMultisampleStateCreateInfo    multisampleParams       = m_multisampleStateParams;
+               const std::vector<VkSampleMask>                 sampleMask                      (multisampleParams.rasterizationSamples / 32, (VkSampleMask)0);
+
+               multisampleParams.pSampleMask = sampleMask.data();
+
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+               minSampleMaskImage = renderer.render();
+       }
+
+       // Render with all flags on
+       {
+               VkPipelineMultisampleStateCreateInfo    multisampleParams       = m_multisampleStateParams;
+               const std::vector<VkSampleMask>                 sampleMask                      (multisampleParams.rasterizationSamples / 32, ~((VkSampleMask)0));
+
+               multisampleParams.pSampleMask = sampleMask.data();
+
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+               maxSampleMaskImage = renderer.render();
+       }
+
+       return verifyImage(testSampleMaskImage->getAccess(), minSampleMaskImage->getAccess(), maxSampleMaskImage->getAccess());
+}
+
+tcu::TestStatus SampleMaskInstance::verifyImage (const tcu::ConstPixelBufferAccess& testSampleMaskImage,
+                                                                                                const tcu::ConstPixelBufferAccess& minSampleMaskImage,
+                                                                                                const tcu::ConstPixelBufferAccess& maxSampleMaskImage)
+{
+       const deUint32  testColorCount  = getUniqueColorsCount(testSampleMaskImage);
+       const deUint32  minColorCount   = getUniqueColorsCount(minSampleMaskImage);
+       const deUint32  maxColorCount   = getUniqueColorsCount(maxSampleMaskImage);
+
+       tcu::TestLog& log = m_context.getTestContext().getLog();
+
+       log << tcu::TestLog::Message
+               << "\nColors found: " << testColorCount << "\n"
+               << "Min. colors expected: " << minColorCount << "\n"
+               << "Max. colors expected: " << maxColorCount << "\n"
+               << tcu::TestLog::EndMessage;
+
+       if (minColorCount > testColorCount || testColorCount > maxColorCount)
+               return tcu::TestStatus::fail("Unique colors out of expected bounds");
+       else
+               return tcu::TestStatus::pass("Unique colors within expected bounds");
+}
+
+tcu::TestStatus testRasterSamplesConsistency (Context& context, GeometryType geometryType)
+{
+       // Use triangle only.
+       DE_UNREF(geometryType);
+
+       const VkSampleCountFlagBits samples[] =
+       {
+               VK_SAMPLE_COUNT_1_BIT,
+               VK_SAMPLE_COUNT_2_BIT,
+               VK_SAMPLE_COUNT_4_BIT,
+               VK_SAMPLE_COUNT_8_BIT,
+               VK_SAMPLE_COUNT_16_BIT,
+               VK_SAMPLE_COUNT_32_BIT,
+               VK_SAMPLE_COUNT_64_BIT
+       };
+
+       const Vertex4RGBA vertexData[3] =
+       {
+               {
+                       tcu::Vec4(-0.75f, 0.0f, 0.0f, 1.0f),
+                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+               },
+               {
+                       tcu::Vec4(0.75f, 0.125f, 0.0f, 1.0f),
+                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+               },
+               {
+                       tcu::Vec4(0.75f, -0.125f, 0.0f, 1.0f),
+                       tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)
+               }
+       };
+
+       const std::vector<Vertex4RGBA>  vertices                        (vertexData, vertexData + 3);
+       deUint32                                                prevUniqueColors        = 2;
+       int                                                             renderCount                     = 0;
+
+       // Do not render with 1 sample (start with samplesNdx = 1).
+       for (int samplesNdx = 1; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+       {
+               if (!isSupportedSampleCount(context.getInstanceInterface(), context.getPhysicalDevice(), samples[samplesNdx]))
+                       continue;
+
+               const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+                       samples[samplesNdx],                                                                            // VkSampleCountFlagBits                                        rasterizationSamples;
+                       false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                           // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+                       false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+                       false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+               };
+
+               MultisampleRenderer                             renderer                (context, VK_FORMAT_R8G8B8A8_UNORM, tcu::IVec2(32, 32), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices, multisampleStateParams, getDefaultColorBlendAttachmentState());
+               de::MovePtr<tcu::TextureLevel>  result                  = renderer.render();
+               const deUint32                                  uniqueColors    = getUniqueColorsCount(result->getAccess());
+
+               renderCount++;
+
+               if (prevUniqueColors > uniqueColors)
+               {
+                       std::ostringstream message;
+
+                       message << "More unique colors generated with " << samples[samplesNdx - 1] << " than with " << samples[samplesNdx];
+                       return tcu::TestStatus::fail(message.str());
+               }
+
+               prevUniqueColors = uniqueColors;
+       }
+
+       if (renderCount == 0)
+               throw tcu::NotSupportedError("Multisampling is unsupported");
+
+       return tcu::TestStatus::pass("Number of unique colors increases as the sample count increases");
+}
+
+
+// AlphaToOneInstance
+
+AlphaToOneInstance::AlphaToOneInstance (Context&                                                                       context,
+                                                                               VkPrimitiveTopology                                                     topology,
+                                                                               const std::vector<Vertex4RGBA>&                         vertices,
+                                                                               const VkPipelineMultisampleStateCreateInfo&     multisampleStateParams,
+                                                                               const VkPipelineColorBlendAttachmentState&      blendState)
+       : vkt::TestInstance                     (context)
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_renderSize                          (32, 32)
+       , m_primitiveTopology           (topology)
+       , m_vertices                            (vertices)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (blendState)
+{
+       VkPhysicalDeviceFeatures deviceFeatures;
+
+       context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &deviceFeatures);
+
+       if (!deviceFeatures.alphaToOne)
+               throw tcu::NotSupportedError("Alpha-to-one is not supported");
+}
+
+tcu::TestStatus AlphaToOneInstance::iterate    (void)
+{
+       DE_ASSERT(m_multisampleStateParams.alphaToOneEnable);
+       DE_ASSERT(m_colorBlendState.blendEnable);
+
+       de::MovePtr<tcu::TextureLevel>  alphaOneImage;
+       de::MovePtr<tcu::TextureLevel>  noAlphaOneImage;
+
+       // Render with blend enabled and alpha to one on
+       {
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+               alphaOneImage = renderer.render();
+       }
+
+       // Render with blend enabled and alpha to one off
+       {
+               VkPipelineMultisampleStateCreateInfo    multisampleParams       = m_multisampleStateParams;
+               multisampleParams.alphaToOneEnable = false;
+
+               MultisampleRenderer renderer (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, multisampleParams, m_colorBlendState);
+               noAlphaOneImage = renderer.render();
+       }
+
+       return verifyImage(alphaOneImage->getAccess(), noAlphaOneImage->getAccess());
+}
+
+tcu::TestStatus AlphaToOneInstance::verifyImage (const tcu::ConstPixelBufferAccess&    alphaOneImage,
+                                                                                                const tcu::ConstPixelBufferAccess&     noAlphaOneImage)
+{
+       for (int y = 0; y < m_renderSize.y(); y++)
+       {
+               for (int x = 0; x < m_renderSize.x(); x++)
+               {
+                       if (!tcu::boolAll(tcu::greaterThanEqual(alphaOneImage.getPixel(x, y), noAlphaOneImage.getPixel(x, y))))
+                       {
+                               std::ostringstream message;
+                               message << "Unsatisfied condition: " << alphaOneImage.getPixel(x, y) << " >= " << noAlphaOneImage.getPixel(x, y);
+                               return tcu::TestStatus::fail(message.str());
+                       }
+               }
+       }
+
+       return tcu::TestStatus::pass("Image rendered with alpha-to-one contains pixels of image rendered with no alpha-to-one");
+}
+
+
+// AlphaToCoverageInstance
+
+AlphaToCoverageInstance::AlphaToCoverageInstance (Context&                                                                             context,
+                                                                                                 VkPrimitiveTopology                                                   topology,
+                                                                                                 const std::vector<Vertex4RGBA>&                               vertices,
+                                                                                                 const VkPipelineMultisampleStateCreateInfo&   multisampleStateParams,
+                                                                                                 const VkPipelineColorBlendAttachmentState&    blendState,
+                                                                                                 GeometryType                                                                  geometryType)
+       : vkt::TestInstance                     (context)
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_renderSize                          (32, 32)
+       , m_primitiveTopology           (topology)
+       , m_vertices                            (vertices)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (blendState)
+       , m_geometryType                        (geometryType)
+{
+}
+
+tcu::TestStatus AlphaToCoverageInstance::iterate (void)
+{
+       DE_ASSERT(m_multisampleStateParams.alphaToCoverageEnable);
+
+       de::MovePtr<tcu::TextureLevel>  result;
+       MultisampleRenderer                             renderer        (m_context, m_colorFormat, m_renderSize, m_primitiveTopology, m_vertices, m_multisampleStateParams, m_colorBlendState);
+
+       result = renderer.render();
+
+       return verifyImage(result->getAccess());
+}
+
+tcu::TestStatus AlphaToCoverageInstance::verifyImage (const tcu::ConstPixelBufferAccess&       result)
+{
+       float maxColorValue;
+
+       switch (m_geometryType)
+       {
+               case GEOMETRY_TYPE_OPAQUE_QUAD:
+                       maxColorValue = 1.01f;
+                       break;
+
+               case GEOMETRY_TYPE_TRANSLUCENT_QUAD:
+                       maxColorValue = 0.5f;
+                       break;
+
+               case GEOMETRY_TYPE_INVISIBLE_QUAD:
+                       maxColorValue = 0.01f;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       for (int y = 0; y < m_renderSize.y(); y++)
+       {
+               for (int x = 0; x < m_renderSize.x(); x++)
+               {
+                       if (result.getPixel(x, y).x() > maxColorValue)
+                       {
+                               std::ostringstream message;
+                               message << "Pixel is not below the threshold value (" << result.getPixel(x, y).x() << " > " << maxColorValue << ")";
+                               return tcu::TestStatus::fail(message.str());
+                       }
+               }
+       }
+
+       return tcu::TestStatus::pass("Image matches reference value");
+}
+
+
+// MultisampleRenderer
+
+MultisampleRenderer::MultisampleRenderer (Context&                                                                             context,
+                                                                                 VkFormat                                                                              colorFormat,
+                                                                                 const tcu::IVec2&                                                             renderSize,
+                                                                                 VkPrimitiveTopology                                                   topology,
+                                                                                 const std::vector<Vertex4RGBA>&                               vertices,
+                                                                                 const VkPipelineMultisampleStateCreateInfo&   multisampleStateParams,
+                                                                                 const VkPipelineColorBlendAttachmentState&    blendState)
+
+       : m_context                                     (context)
+       , m_colorFormat                         (colorFormat)
+       , m_renderSize                          (renderSize)
+       , m_multisampleStateParams      (multisampleStateParams)
+       , m_colorBlendState                     (blendState)
+{
+       if (!isSupportedSampleCount(context.getInstanceInterface(), context.getPhysicalDevice(), multisampleStateParams.rasterizationSamples))
+               throw tcu::NotSupportedError("Unsupported number of rasterization samples");
+
+       const DeviceInterface&          vk                                              = context.getDeviceInterface();
+       const VkDevice                          vkDevice                                = context.getDevice();
+       const deUint32                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                         memAlloc                                (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+       const VkComponentMapping        componentMappingRGBA    = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+       // Create color image
+       {
+               const VkImageCreateInfo colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+                       m_colorFormat,                                                                                                                          // VkFormat                                     format;
+                       { m_renderSize.x(), m_renderSize.y(), 1u },                                                                     // VkExtent3D                           extent;
+                       1u,                                                                                                                                                     // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                     arrayLayers;
+                       m_multisampleStateParams.rasterizationSamples,                                                          // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        initialLayout;
+               };
+
+               m_colorImage                    = createImage(vk, vkDevice, &colorImageParams);
+
+               // Allocate and bind color image memory
+               m_colorImageAlloc               = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+       }
+
+       // Create resolve image
+       {
+               const VkImageCreateInfo resolveImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                                    // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                                // const void*                          pNext;
+                       0u,                                                                                                                                                             // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                               // VkImageType                          imageType;
+                       m_colorFormat,                                                                                                                                  // VkFormat                                     format;
+                       { m_renderSize.x(), m_renderSize.y(), 1u },                                                                             // VkExtent3D                           extent;
+                       1u,                                                                                                                                                             // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                             // deUint32                                     arrayLayers;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                                  // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                                // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |                 // VkImageUsageFlags            usage;
+                               VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                              // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                             // deUint32                                     queueFamilyIndexCount;
+                       &queueFamilyIndex,                                                                                                                              // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED                                                                                                               // VkImageLayout                        initialLayout;
+               };
+
+               m_resolveImage = createImage(vk, vkDevice, &resolveImageParams);
+
+               // Allocate and bind resolve image memory
+               m_resolveImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_resolveImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *m_resolveImage, m_resolveImageAlloc->getMemory(), m_resolveImageAlloc->getOffset()));
+       }
+
+       // Create color attachment view
+       {
+               const VkImageViewCreateInfo colorAttachmentViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,               // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       0u,                                                                                             // VkImageViewCreateFlags       flags;
+                       *m_colorImage,                                                                  // VkImage                                      image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                  // VkImageViewType                      viewType;
+                       m_colorFormat,                                                                  // VkFormat                                     format;
+                       componentMappingRGBA,                                                   // VkComponentMapping           components;
+                       { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }   // VkImageSubresourceRange      subresourceRange;
+               };
+
+               m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+       }
+
+       // Create resolve attachment view
+       {
+               const VkImageViewCreateInfo resolveAttachmentViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,               // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       0u,                                                                                             // VkImageViewCreateFlags       flags;
+                       *m_resolveImage,                                                                // VkImage                                      image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                  // VkImageViewType                      viewType;
+                       m_colorFormat,                                                                  // VkFormat                                     format;
+                       componentMappingRGBA,                                                   // VkComponentMapping           components;
+                       { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }   // VkImageSubresourceRange      subresourceRange;
+               };
+
+               m_resolveAttachmentView = createImageView(vk, vkDevice, &resolveAttachmentViewParams);
+       }
+
+       // Create render pass
+       {
+               const VkAttachmentDescription attachmentDescriptions[2] =
+               {
+                       {
+                               0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
+                               m_colorFormat,                                                                          // VkFormat                                                     format;
+                               m_multisampleStateParams.rasterizationSamples,          // 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;
+                       },
+                       {
+                               0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
+                               m_colorFormat,                                                                          // 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 colorAttachmentReference =
+               {
+                       0u,                                                                                                     // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
+               };
+
+               const VkAttachmentReference resolveAttachmentReference =
+               {
+                       1u,                                                                                                     // 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;
+                       &colorAttachmentReference,                                                              // const VkAttachmentReference* pColorAttachments;
+                       &resolveAttachmentReference,                                                    // 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;
+                       2u,                                                                                                     // deUint32                                                     attachmentCount;
+                       attachmentDescriptions,                                                         // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               const VkImageView attachments[2] =
+               {
+                       *m_colorAttachmentView,
+                       *m_resolveAttachmentView
+               };
+
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags             flags;
+                       *m_renderPass,                                                                          // VkRenderPass                                 renderPass;
+                       2u,                                                                                                     // deUint32                                             attachmentCount;
+                       attachments,                                                                            // const VkImageView*                   pAttachments;
+                       (deUint32)m_renderSize.x(),                                                     // deUint32                                             width;
+                       (deUint32)m_renderSize.y(),                                                     // deUint32                                             height;
+                       1u                                                                                                      // deUint32                                             layers;
+               };
+
+               m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // const void*                                          pNext;
+                       0u,                                                                                                     // VkPipelineLayoutCreateFlags          flags;
+                       0u,                                                                                                     // deUint32                                                     setLayoutCount;
+                       DE_NULL,                                                                                        // const VkDescriptorSetLayout*         pSetLayouts;
+                       0u,                                                                                                     // deUint32                                                     pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*           pPushConstantRanges;
+               };
+
+               m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       m_vertexShaderModule    = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+       m_fragmentShaderModule  = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+       // Create pipeline
+       {
+               const VkPipelineShaderStageCreateInfo shaderStageParams[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;
+                               *m_vertexShaderModule,                                                                          // 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;
+                               *m_fragmentShaderModule,                                                                        // VkShaderModule                                               module;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       }
+               };
+
+               const VkVertexInputBindingDescription vertexInputBindingDescription =
+               {
+                       0u,                                                                     // deUint32                             binding;
+                       sizeof(Vertex4RGBA),                            // deUint32                             stride;
+                       VK_VERTEX_INPUT_RATE_VERTEX                     // VkVertexInputRate    inputRate;
+               };
+
+               const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
+               {
+                       {
+                               0u,                                                                     // deUint32     location;
+                               0u,                                                                     // deUint32     binding;
+                               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                               0u                                                                      // deUint32     offset;
+                       },
+                       {
+                               1u,                                                                     // deUint32     location;
+                               0u,                                                                     // deUint32     binding;
+                               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                               DE_OFFSET_OF(Vertex4RGBA, color),       // deUint32     offset;
+                       }
+               };
+
+               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;
+                       &vertexInputBindingDescription,                                                                 // const VkVertexInputBindingDescription*       pVertexBindingDescriptions;
+                       2u,                                                                                                                             // deUint32                                                                     vertexAttributeDescriptionCount;
+                       vertexInputAttributeDescriptions                                                                // 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;
+                       topology,                                                                                                               // VkPrimitiveTopology                                          topology;
+                       false                                                                                                                   // VkBool32                                                                     primitiveRestartEnable;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        x;
+                       0.0f,                                           // float        y;
+                       (float)m_renderSize.x(),        // float        width;
+                       (float)m_renderSize.y(),        // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor =
+               {
+                       { 0, 0 },                                                                                               // VkOffset2D  offset;
+                       { m_renderSize.x(), m_renderSize.y() }                                  // 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                                                             scissorCount;
+                       &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;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     depthBiasEnable;
+                       0.0f,                                                                                                                   // float                                                                        depthBiasConstantFactor;
+                       0.0f,                                                                                                                   // float                                                                        depthBiasClamp;
+                       0.0f,                                                                                                                   // float                                                                        depthBiasSlopeFactor;
+                       1.0f                                                                                                                    // float                                                                        lineWidth;
+               };
+
+               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;
+                       &m_colorBlendState,                                                                                     // const VkPipelineColorBlendAttachmentState*   pAttachments;
+                       { 0.0f, 0.0f, 0.0f, 0.0f }                                                                      // float                                                                                blendConstants[4];
+               };
+
+               const VkPipelineDynamicStateCreateInfo  dynamicStateParams              =
+               {
+                       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 VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineDepthStencilStateCreateFlags       flags;
+                       false,                                                                                                          // VkBool32                                                                     depthTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     depthWriteEnable;
+                       VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                                                          depthCompareOp;
+                       false,                                                                                                          // VkBool32                                                                     depthBoundsTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     stencilTestEnable;
+                       // VkStencilOpState     front;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       // VkStencilOpState     back;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       -1.0f,                                                                                                          // float                        minDepthBounds;
+                       +1.0f,                                                                                                          // float                        maxDepthBounds;
+               };
+
+               const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       0u,                                                                                                     // VkPipelineCreateFlags                                                        flags;
+                       2u,                                                                                                     // deUint32                                                                                     stageCount;
+                       shaderStageParams,                                                                      // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
+                       &m_multisampleStateParams,                                                      // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &depthStencilStateParams,                                                       // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateParams,                                                            // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *m_pipelineLayout,                                                                      // VkPipelineLayout                                                                     layout;
+                       *m_renderPass,                                                                          // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               m_graphicsPipeline      = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create vertex buffer
+       {
+               const VkBufferCreateInfo vertexBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkBufferCreateFlags  flags;
+                       1024u,                                                                          // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                      // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                     // deUint32                             queueFamilyIndexCount;
+                       &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+
+               m_vertexBuffer          = createBuffer(vk, vkDevice, &vertexBufferParams);
+               m_vertexBufferAlloc     = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+               // Load vertices into vertex buffer
+               deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(Vertex4RGBA));
+               flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,             // VkStructureType                              sType;
+                       DE_NULL,                                                                                // const void*                                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                   // VkCommandPoolCreateFlags             flags;
+                       queueFamilyIndex,                                                               // deUint32                                             queueFamilyIndex;
+               };
+
+               m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *m_cmdPool,                                                                             // VkCommandPool                        commandPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCommandBufferLevel level;
+                       1u                                                                                              // deUint32                             bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCommandBufferUsageFlags            flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       false,                                                                                  // VkBool32                                                     occlusionQueryEnable;
+                       0u,                                                                                             // VkQueryControlFlags                          queryFlags;
+                       0u                                                                                              // VkQueryPipelineStatisticFlags        pipelineStatistics;
+               };
+
+               VkClearValue colorClearValue;
+               colorClearValue.color.float32[0] = 0.0f;
+               colorClearValue.color.float32[1] = 0.0f;
+               colorClearValue.color.float32[2] = 0.0f;
+               colorClearValue.color.float32[3] = 0.0f;
+
+               const VkClearValue clearValues[2] =
+               {
+                       colorClearValue,
+                       colorClearValue
+               };
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *m_renderPass,                                                                                  // VkRenderPass                 renderPass;
+                       *m_framebuffer,                                                                                 // VkFramebuffer                framebuffer;
+                       { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },   // VkRect2D                             renderArea;
+                       2,                                                                                                              // deUint32                             clearValueCount;
+                       clearValues                                                                                             // const VkClearValue*  pClearValues;
+               };
+
+               m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+               VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               VkDeviceSize vertexBufferOffset = 0u;
+
+               vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+               vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+               vk.cmdDraw(*m_cmdBuffer, (deUint32)vertices.size(), 1, 0, 0);
+
+               vk.cmdEndRenderPass(*m_cmdBuffer);
+
+               VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               m_fence = createFence(vk, vkDevice, &fenceParams);
+       }
+}
+
+MultisampleRenderer::~MultisampleRenderer (void)
+{
+}
+
+de::MovePtr<tcu::TextureLevel> MultisampleRenderer::render (void)
+{
+       const DeviceInterface&          vk                                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice                        = m_context.getDevice();
+       const VkQueue                           queue                           = m_context.getUniversalQueue();
+       const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                         allocator                       (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+       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;
+               &m_cmdBuffer.get(),                             // const VkCommandBuffer*       pCommandBuffers;
+               0u,                                                             // deUint32                                     signalSemaphoreCount;
+               DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+       };
+
+       VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+       VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+       return readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_resolveImage, m_colorFormat, m_renderSize);
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createMultisampleTests (tcu::TestContext& testCtx)
+{
+       const VkSampleCountFlagBits samples[] =
+       {
+               VK_SAMPLE_COUNT_2_BIT,
+               VK_SAMPLE_COUNT_4_BIT,
+               VK_SAMPLE_COUNT_8_BIT,
+               VK_SAMPLE_COUNT_16_BIT,
+               VK_SAMPLE_COUNT_32_BIT,
+               VK_SAMPLE_COUNT_64_BIT
+       };
+
+       de::MovePtr<tcu::TestCaseGroup> multisampleTests (new tcu::TestCaseGroup(testCtx, "multisample", ""));
+
+       // Rasterization samples tests
+       {
+               de::MovePtr<tcu::TestCaseGroup> rasterizationSamplesTests(new tcu::TestCaseGroup(testCtx, "raster_samples", ""));
+
+               for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+               {
+                       std::ostringstream caseName;
+                       caseName << "samples_" << samples[samplesNdx];
+
+                       de::MovePtr<tcu::TestCaseGroup> samplesTests    (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+                       samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_triangle", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+                       samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_line", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_LINE));
+                       samplesTests->addChild(new RasterizationSamplesTest(testCtx, "primitive_point", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_POINT));
+
+                       rasterizationSamplesTests->addChild(samplesTests.release());
+               }
+
+               multisampleTests->addChild(rasterizationSamplesTests.release());
+       }
+
+       // Raster samples consistency check
+       {
+               de::MovePtr<tcu::TestCaseGroup> rasterSamplesConsistencyTests(new tcu::TestCaseGroup(testCtx, "raster_samples_consistency", ""));
+
+               addFunctionCaseWithPrograms(rasterSamplesConsistencyTests.get(),
+                                                                       "unique_colors_check",
+                                                                       "",
+                                                                       initMultisamplePrograms,
+                                                                       testRasterSamplesConsistency,
+                                                                       GEOMETRY_TYPE_OPAQUE_TRIANGLE);
+
+               multisampleTests->addChild(rasterSamplesConsistencyTests.release());
+       }
+
+       // minSampleShading tests
+       {
+               struct TestConfig
+               {
+                       const char*     name;
+                       float           minSampleShading;
+               };
+
+               const TestConfig testConfigs[] =
+               {
+                       { "min_0_0",    0.0f },
+                       { "min_0_25",   0.25f },
+                       { "min_0_5",    0.5f },
+                       { "min_0_75",   0.75f },
+                       { "min_1_0",    1.0f }
+               };
+
+               de::MovePtr<tcu::TestCaseGroup> minSampleShadingTests(new tcu::TestCaseGroup(testCtx, "min_sample_shading", ""));
+
+               for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(testConfigs); configNdx++)
+               {
+                       const TestConfig&                               testConfig                              = testConfigs[configNdx];
+                       de::MovePtr<tcu::TestCaseGroup> minShadingValueTests    (new tcu::TestCaseGroup(testCtx, testConfigs[configNdx].name, ""));
+
+                       for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+                       {
+                               std::ostringstream caseName;
+                               caseName << "samples_" << samples[samplesNdx];
+
+                               de::MovePtr<tcu::TestCaseGroup> samplesTests    (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+                               samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_triangle", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+                               samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_line", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_LINE));
+                               samplesTests->addChild(new MinSampleShadingTest(testCtx, "primitive_point", "", samples[samplesNdx], testConfig.minSampleShading, GEOMETRY_TYPE_OPAQUE_POINT));
+
+                               minShadingValueTests->addChild(samplesTests.release());
+                       }
+
+                       minSampleShadingTests->addChild(minShadingValueTests.release());
+               }
+
+               multisampleTests->addChild(minSampleShadingTests.release());
+       }
+
+       // pSampleMask tests
+       {
+               struct TestConfig
+               {
+                       const char*             name;
+                       const char*             description;
+                       VkSampleMask    sampleMask;
+               };
+
+               const TestConfig testConfigs[] =
+               {
+                       { "mask_all_on",        "All mask bits are off",                        0x0 },
+                       { "mask_all_off",       "All mask bits are on",                         0xFFFFFFFF },
+                       { "mask_one",           "All mask elements are 0x1",            0x1},
+                       { "mask_random",        "All mask elements are 0xAAAAAAAA",     0xAAAAAAAA },
+               };
+
+               de::MovePtr<tcu::TestCaseGroup> sampleMaskTests(new tcu::TestCaseGroup(testCtx, "sample_mask", ""));
+
+               for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(testConfigs); configNdx++)
+               {
+                       const TestConfig&                               testConfig                              = testConfigs[configNdx];
+                       de::MovePtr<tcu::TestCaseGroup> sampleMaskValueTests    (new tcu::TestCaseGroup(testCtx, testConfig.name, testConfig.description));
+
+                       for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+                       {
+                               std::ostringstream caseName;
+                               caseName << "samples_" << samples[samplesNdx];
+
+                               const deUint32                                  sampleMaskCount = samples[samplesNdx] / 32;
+                               de::MovePtr<tcu::TestCaseGroup> samplesTests    (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+                               std::vector<VkSampleMask> mask;
+                               for (deUint32 maskNdx = 0; maskNdx < sampleMaskCount; maskNdx++)
+                                       mask.push_back(testConfig.sampleMask);
+
+                               samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_triangle", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_TRIANGLE));
+                               samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_line", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_LINE));
+                               samplesTests->addChild(new SampleMaskTest(testCtx, "primitive_point", "", samples[samplesNdx], mask, GEOMETRY_TYPE_OPAQUE_POINT));
+
+                               sampleMaskValueTests->addChild(samplesTests.release());
+                       }
+
+                       sampleMaskTests->addChild(sampleMaskValueTests.release());
+               }
+
+               multisampleTests->addChild(sampleMaskTests.release());
+
+       }
+
+       // AlphaToOne tests
+       {
+               de::MovePtr<tcu::TestCaseGroup> alphaToOneTests(new tcu::TestCaseGroup(testCtx, "alpha_to_one", ""));
+
+               for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+               {
+                       std::ostringstream caseName;
+                       caseName << "samples_" << samples[samplesNdx];
+
+                       alphaToOneTests->addChild(new AlphaToOneTest(testCtx, caseName.str(), "", samples[samplesNdx]));
+               }
+
+               multisampleTests->addChild(alphaToOneTests.release());
+       }
+
+       // AlphaToCoverageEnable tests
+       {
+               de::MovePtr<tcu::TestCaseGroup> alphaToCoverageTests (new tcu::TestCaseGroup(testCtx, "alpha_to_coverage", ""));
+
+               for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
+               {
+                       std::ostringstream caseName;
+                       caseName << "samples_" << samples[samplesNdx];
+
+                       de::MovePtr<tcu::TestCaseGroup> samplesTests    (new tcu::TestCaseGroup(testCtx, caseName.str().c_str(), ""));
+
+                       samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_opaque", "", samples[samplesNdx], GEOMETRY_TYPE_OPAQUE_QUAD));
+                       samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_translucent", "", samples[samplesNdx], GEOMETRY_TYPE_TRANSLUCENT_QUAD));
+                       samplesTests->addChild(new AlphaToCoverageTest(testCtx, "alpha_invisible", "", samples[samplesNdx], GEOMETRY_TYPE_INVISIBLE_QUAD));
+
+                       alphaToCoverageTests->addChild(samplesTests.release());
+               }
+               multisampleTests->addChild(alphaToCoverageTests.release());
+       }
+
+       return multisampleTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineMultisampleTests.hpp
new file mode 100644 (file)
index 0000000..db5ed3b
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEMULTISAMPLETESTS_HPP
+#define _VKTPIPELINEMULTISAMPLETESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Multisample Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createMultisampleTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEMULTISAMPLETESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.cpp
new file mode 100644 (file)
index 0000000..dd2beb2
--- /dev/null
@@ -0,0 +1,1574 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 ARM Limited.
+ *
+ * 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 PushConstant Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelinePushConstantTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deMemory.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+enum
+{
+       TRIANGLE_COUNT  = 2,
+       MAX_RANGE_COUNT = 5
+};
+
+enum RangeSizeCase
+{
+       SIZE_CASE_4     = 0,
+       SIZE_CASE_16,
+       SIZE_CASE_40,
+       SIZE_CASE_128,
+       SIZE_CASE_UNSUPPORTED
+};
+       
+struct PushConstantData
+{
+       struct PushConstantRange
+       {
+               VkShaderStageFlags              shaderStage;
+               deUint32                                offset;
+               deUint32                                size;
+       } range;
+       struct PushConstantUpdate
+       {
+               deUint32                                offset;
+               deUint32                                size;
+       } update;
+};
+
+class PushConstantGraphicsTest : public vkt::TestCase
+{
+public:
+                                                       PushConstantGraphicsTest        (tcu::TestContext&                      testContext,
+                                                                                                                const std::string&                     name,
+                                                                                                                const std::string&                     description,
+                                                                                                                const deUint32                         rangeCount,
+                                                                                                                const PushConstantData         pushConstantRange[MAX_RANGE_COUNT],
+                                                                                                                const deBool                           multipleUpdate);
+       virtual                                 ~PushConstantGraphicsTest       (void);
+       virtual void                    initPrograms                            (SourceCollections& sourceCollections) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+       RangeSizeCase                   getRangeSizeCase                        (deUint32 rangeSize) const;
+
+private:
+       const deUint32                  m_rangeCount;
+       PushConstantData                m_pushConstantRange[MAX_RANGE_COUNT];
+       const deBool                    m_multipleUpdate;
+};
+
+class PushConstantGraphicsTestInstance : public vkt::TestInstance
+{
+public:
+                                                               PushConstantGraphicsTestInstance        (Context&                                       context,
+                                                                                                                                        const deUint32                         rangeCount,
+                                                                                                                                        const PushConstantData         pushConstantRange[MAX_RANGE_COUNT],
+                                                                                                                                        const deBool                           multipleUpdate);
+       virtual                                         ~PushConstantGraphicsTestInstance       (void);
+       virtual tcu::TestStatus         iterate                                                         (void);
+       
+       void                                            createShaderStage                                       (const DeviceInterface&         vk,
+                                                                                                                                        VkDevice                                       device,
+                                                                                                                                        const BinaryCollection&        programCollection,
+                                                                                                                                        const char*                            name,
+                                                                                                                                        VkShaderStageFlagBits          stage,
+                                                                                                                                        Move<VkShaderModule>*          module);
+       std::vector<Vertex4RGBA>        createQuad                                                      (const float size);
+       
+private:
+       tcu::TestStatus                         verifyImage                                                     (void);
+
+private:
+       const tcu::IVec2                                                                m_renderSize;
+       const VkFormat                                                                  m_colorFormat;
+       const deUint32                                                                  m_rangeCount;
+       PushConstantData                                                                m_pushConstantRange[MAX_RANGE_COUNT];
+       const deBool                                                                    m_multipleUpdate;
+
+       VkImageCreateInfo                                                               m_colorImageCreateInfo;
+       Move<VkImage>                                                                   m_colorImage;
+       de::MovePtr<Allocation>                                                 m_colorImageAlloc;
+       Move<VkImageView>                                                               m_colorAttachmentView;
+       Move<VkRenderPass>                                                              m_renderPass;
+       Move<VkFramebuffer>                                                             m_framebuffer;
+
+       Move<VkShaderModule>                                                    m_vertexShaderModule;
+       Move<VkShaderModule>                                                    m_fragmentShaderModule;
+       Move<VkShaderModule>                                                    m_geometryShaderModule;
+       Move<VkShaderModule>                                                    m_tessControlShaderModule;
+       Move<VkShaderModule>                                                    m_tessEvaluationShaderModule;
+
+       VkShaderStageFlags                                                              m_shaderFlags;
+       std::vector<VkPipelineShaderStageCreateInfo>    m_shaderStage;
+
+       Move<VkBuffer>                                                                  m_vertexBuffer;
+       std::vector<Vertex4RGBA>                                                m_vertices;
+       de::MovePtr<Allocation>                                                 m_vertexBufferAlloc;
+
+       Move<VkBuffer>                                                                  m_uniformBuffer;
+       de::MovePtr<Allocation>                                                 m_uniformBufferAlloc;
+       Move<VkDescriptorPool>                                                  m_descriptorPool;
+       Move<VkDescriptorSetLayout>                                             m_descriptorSetLayout;
+       Move<VkDescriptorSet>                                                   m_descriptorSet;
+       
+       Move<VkPipelineLayout>                                                  m_pipelineLayout;
+       Move<VkPipeline>                                                                m_graphicsPipelines;
+
+       Move<VkCommandPool>                                                             m_cmdPool;
+       Move<VkCommandBuffer>                                                   m_cmdBuffer;
+
+       Move<VkFence>                                                                   m_fence;
+};
+
+PushConstantGraphicsTest::PushConstantGraphicsTest (tcu::TestContext&                  testContext,
+                                                                                                       const std::string&                      name,
+                                                                                                       const std::string&                      description,
+                                                                                                       const deUint32                          rangeCount,
+                                                                                                       const PushConstantData          pushConstantRange[MAX_RANGE_COUNT],
+                                                                                                       const deBool                            multipleUpdate)
+       : vkt::TestCase         (testContext, name, description)
+       , m_rangeCount          (rangeCount)
+       , m_multipleUpdate      (multipleUpdate)
+{
+       deMemcpy(m_pushConstantRange, pushConstantRange, sizeof(PushConstantData) * MAX_RANGE_COUNT);
+}
+
+PushConstantGraphicsTest::~PushConstantGraphicsTest (void)
+{
+}
+
+TestInstance* PushConstantGraphicsTest::createInstance (Context& context) const
+{
+       return new PushConstantGraphicsTestInstance(context, m_rangeCount, m_pushConstantRange, m_multipleUpdate);
+}
+
+RangeSizeCase PushConstantGraphicsTest::getRangeSizeCase (deUint32 rangeSize) const
+{
+       switch (rangeSize)
+       {
+               case 4:
+                       return SIZE_CASE_4;
+               case 16:
+                       return SIZE_CASE_16;
+               case 40:
+                       return SIZE_CASE_40;
+               case 128:
+                       return SIZE_CASE_128;
+               default:
+                       DE_FATAL("Range size unsupported yet");
+                       return SIZE_CASE_UNSUPPORTED;
+       }
+}
+
+void PushConstantGraphicsTest::initPrograms (SourceCollections& sourceCollections) const
+{
+       std::ostringstream      vertexSrc;
+       std::ostringstream      fragmentSrc;
+       std::ostringstream      geometrySrc;
+       std::ostringstream      tessControlSrc;
+       std::ostringstream      tessEvaluationSrc;
+       
+       for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+       {
+               if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_VERTEX_BIT)
+               {
+                       vertexSrc << "#version 450\n"
+                                         << "layout(location = 0) in highp vec4 position;\n"
+                                         << "layout(location = 1) in highp vec4 color;\n"
+                                         << "layout(location = 0) out highp vec4 vtxColor;\n"
+                                         << "layout(push_constant) uniform Material {\n";
+                 
+                       switch (getRangeSizeCase(m_pushConstantRange[rangeNdx].range.size))
+                       {
+                               case SIZE_CASE_4:
+                                       vertexSrc << "int kind;\n"
+                                                         << "} matInst;\n";
+                                       break;
+                               case SIZE_CASE_16:
+                                       vertexSrc << "vec4 color;\n"
+                                                         << "} matInst;\n"
+                                                         << "layout(location = 0) uniform UniformBuf {\n"
+                                                         << "vec4 element;\n"
+                                                         << "} uniformBuf;\n";
+                                       break;
+                               case SIZE_CASE_40:
+                                       vertexSrc << "int kind;\n"
+                                                         << "vec4 color;\n"
+                                                         << "} matInst[2];\n";
+                                       break;
+                               case SIZE_CASE_128:
+                                       vertexSrc << "vec4 color[8];\n"
+                                                         << "} matInst;\n";
+                                       break;
+                               default:
+                                       DE_FATAL("Not implemented yet");
+                                       break;
+                       }
+                 
+                       vertexSrc << "void main()\n"
+                                         << "{\n"
+                                         << "  gl_Position = position;\n";
+                 
+                       switch (getRangeSizeCase(m_pushConstantRange[rangeNdx].range.size))
+                       {
+                               case SIZE_CASE_4:
+                                       vertexSrc << "switch (matInst.kind) {\n"
+                                                         << "case 0: vtxColor = vec4(0.0, 1.0, 0, 1.0); break;\n"
+                                                         << "case 1: vtxColor = vec4(0.0, 0.0, 1.0, 1.0); break;\n"
+                                                         << "case 2: vtxColor = vec4(1.0, 0.0, 0, 1.0); break;\n"
+                                                         << "default: vtxColor = color; break;}\n"
+                                                         << "}\n"; 
+                                       break;
+                               case SIZE_CASE_16:
+                                       vertexSrc << "vtxColor = (matInst.color + uniformBuf.element) * 0.5;\n"
+                                                         << "}\n";
+                                       break;
+                               case SIZE_CASE_40:
+                                       vertexSrc << "vtxColor = matInst[1].color;\n"
+                                                         << "}\n";
+                                       break;
+                               case SIZE_CASE_128:
+                                       vertexSrc << "vec4 color = vec4(0.0, 0, 0, 0.0);\n"
+                                                         << "for (int i = 0; i < 8; i++)\n"
+                                                         << "{\n"
+                                                         << "  color = color + matInst.color[i];\n"
+                                                         << "}\n"
+                                                         << "vtxColor = color * 0.125;\n"
+                                                         << "}\n";
+                                       break;
+                               default:
+                                       DE_FATAL("Not implemented yet");
+                                       break;
+                       }
+                       
+                       sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSrc.str());
+               }
+               
+               if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+               {
+                       tessControlSrc << "#version 450\n"
+                                                  << "layout (vertices = 3) out;\n"
+                                                  << "layout(push_constant) uniform TessLevel {\n"
+                                                  << "    layout(offset = 24) int level;\n"
+                                                  << "} tessLevel;\n"
+                                                  << "in highp vec4 color[];\n"
+                                                  << "out highp vec4 vtxColor[];\n"
+                                                  << "void main()\n"
+                                                  << "{\n"
+                                                  << "  gl_TessLevelInner[0] = tessLevel.level;\n"
+                                                  << "  gl_TessLevelOuter[0] = tessLevel.level;\n"
+                                                  << "  gl_TessLevelOuter[1] = tessLevel.level;\n"
+                                                  << "  gl_TessLevelOuter[2] = tessLevel.level;\n"
+                                                  << "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+                                                  << "  vtxColor[gl_InvocationID] = color[gl_InvocationID];\n"
+                                                  << "}\n";
+                                               
+                       sourceCollections.glslSources.add("color_tesc") << glu::TessellationControlSource(tessControlSrc.str());
+               }
+               
+               if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+               {
+                       tessEvaluationSrc << "#version 450\n"
+                                                         << "layout (triangles) in;\n"
+                                                         << "layout(push_constant) uniform Material {\n"
+                                                         << "    layout(offset = 28) vec4 color;\n"
+                                                         << "} matInst;\n"
+                                                         << "in highp vec4 color[];\n"
+                                                         << "out highp vec4 vtxColor;\n"
+                                                         << "void main()\n"
+                                                         << "{\n"
+                                                         << "  gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
+                                                         << "  vtxColor = matInst.color;\n"
+                                                         << "}\n";
+                                               
+                       sourceCollections.glslSources.add("color_tese") << glu::TessellationEvaluationSource(tessEvaluationSrc.str());
+               }
+               
+               if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_GEOMETRY_BIT)
+               {
+                       geometrySrc << "#version 450\n"
+                                               << "layout(triangles) in;\n"
+                                               << "layout(triangle_strip, max_vertices=3) out;\n"
+                                               << "layout(push_constant) uniform Material {\n"
+                                               << "    layout(offset = 20) int kind;\n"
+                                               << "} matInst;\n"
+                                               << "in highp vec4 color[];\n"
+                                               << "out highp vec4 vtxColor;\n"
+                                               << "void main()\n"
+                                               << "{\n"
+                                               << "  for(int i=0; i<3; i++)\n"
+                                               << "  {\n"
+                                               << "    gl_Position.xyz = gl_in[i].gl_Position.xyz / matInst.kind;\n"
+                                               << "    gl_Position.w = gl_in[i].gl_Position.w;\n"
+                                               << "    vtxColor = color[i];\n"
+                                               << "    EmitVertex();\n"
+                                               << "  }\n"
+                                               << "  EndPrimitive();\n"
+                                               << "}\n";
+                                               
+                       sourceCollections.glslSources.add("color_geom") << glu::GeometrySource(geometrySrc.str());
+               }
+               
+               if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT)
+               {
+                       fragmentSrc << "#version 450\n"
+                                               << "layout(location = 0) in highp vec4 vtxColor;\n"
+                                               << "layout(location = 0) out highp vec4 fragColor;\n"
+                                               << "layout(push_constant) uniform Material {\n";
+                                               
+                       if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_VERTEX_BIT)
+                       {
+                               fragmentSrc << "    layout(offset = 0) int kind;\n"
+                                                       << "} matInst;\n";
+                       }
+                       else
+                       {
+                               fragmentSrc << "    layout(offset = 16) int kind;\n"
+                                                       << "} matInst;\n";
+                       }
+                                               
+                       fragmentSrc << "void main (void)\n"
+                                               << "{\n"
+                                               << "    switch (matInst.kind) {\n"
+                                               << "    case 0: fragColor = vec4(0, 1.0, 0, 1.0); break;\n"
+                                               << "    case 1: fragColor = vec4(0, 0.0, 1.0, 1.0); break;\n"
+                                               << "    case 2: fragColor = vtxColor; break;\n"
+                                               << "    default: fragColor = vec4(1.0, 1.0, 1.0, 1.0); break;}\n"
+                                               << "}\n";
+                                               
+                       sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSrc.str());
+               }
+       }
+       
+       // add a pass through fragment shader if it's not activated in push constant ranges
+       if (fragmentSrc.str().empty())
+       {
+               fragmentSrc << "#version 450\n"
+                                       << "layout(location = 0) in highp vec4 vtxColor;\n"
+                                       << "layout(location = 0) out highp vec4 fragColor;\n"
+                                       << "void main (void)\n"
+                                       << "{\n"
+                                       << "    fragColor = vtxColor;\n"
+                                       << "}\n";
+                   
+               sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSrc.str());
+       }
+}
+
+void PushConstantGraphicsTestInstance::createShaderStage (const DeviceInterface&       vk,
+                                                                                                                 VkDevice                                      device,
+                                                                                                                 const BinaryCollection&       programCollection,
+                                                                                                                 const char*                           name,
+                                                                                                                 VkShaderStageFlagBits         stage,
+                                                                                                                 Move<VkShaderModule>*         module)
+{
+       *module = createShaderModule(vk, device, programCollection.get(name), 0);
+       
+       const vk::VkPipelineShaderStageCreateInfo       stageCreateInfo =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                              sType;
+               DE_NULL,                                                                                                // const void*                                                  pNext;
+               0u,                                                                                                             // VkPipelineShaderStageCreateFlags             flags;
+               stage,                                                                                                  // VkShaderStageFlagBits                                stage;
+               **module,                                                                                               // VkShaderModule                                               module;
+               "main",                                                                                                 // const char*                                                  pName;
+               DE_NULL                                                                                                 // const VkSpecializationInfo*                  pSpecializationInfo;
+       };
+       
+       m_shaderStage.push_back(stageCreateInfo);
+}
+
+std::vector<Vertex4RGBA> PushConstantGraphicsTestInstance::createQuad(const float size)
+{
+       std::vector<Vertex4RGBA>        vertices;
+       
+       const tcu::Vec4                         color                           = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+       const Vertex4RGBA                       lowerLeftVertex         = {tcu::Vec4(-size, -size, 0.0f, 1.0f), color};
+       const Vertex4RGBA                       lowerRightVertex        = {tcu::Vec4(size, -size, 0.0f, 1.0f), color};
+       const Vertex4RGBA                       UpperLeftVertex         = {tcu::Vec4(-size, size, 0.0f, 1.0f), color};
+       const Vertex4RGBA                       UpperRightVertex        = {tcu::Vec4(size, size, 0.0f, 1.0f), color};
+       
+       vertices.push_back(lowerLeftVertex);
+       vertices.push_back(lowerRightVertex);
+       vertices.push_back(UpperLeftVertex);
+       vertices.push_back(UpperLeftVertex);
+       vertices.push_back(lowerRightVertex);
+       vertices.push_back(UpperRightVertex);
+       
+       return vertices;
+}
+
+PushConstantGraphicsTestInstance::PushConstantGraphicsTestInstance (Context&                                   context,
+                                                                                                                                       const deUint32                          rangeCount,
+                                                                                                                                       const PushConstantData          pushConstantRange[MAX_RANGE_COUNT],
+                                                                                                                                       deBool                                          multipleUpdate)
+       : vkt::TestInstance             (context)
+       , m_renderSize                  (32, 32)
+       , m_colorFormat                 (VK_FORMAT_R8G8B8A8_UNORM)
+       , m_rangeCount                  (rangeCount)
+       , m_multipleUpdate              (multipleUpdate)
+       , m_shaderFlags                 (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
+{
+       const DeviceInterface&          vk                                              = context.getDeviceInterface();
+       const VkDevice                          vkDevice                                = context.getDevice();
+       const deUint32                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                         memAlloc                                (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+       const VkComponentMapping        componentMappingRGBA    = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+       deMemcpy(m_pushConstantRange, pushConstantRange, sizeof(PushConstantData) * MAX_RANGE_COUNT);
+       
+       // Create color image
+       {
+               const VkImageCreateInfo colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+                       m_colorFormat,                                                                                                                          // VkFormat                                     format;
+                       { m_renderSize.x(), m_renderSize.y(), 1u },                                                                     // VkExtent3D                           extent;
+                       1u,                                                                                                                                                     // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                     arrayLayers;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        initialLayout;
+               };
+
+               m_colorImageCreateInfo  = colorImageParams;
+               m_colorImage                    = createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+               // Allocate and bind color image memory
+               m_colorImageAlloc               = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+       }
+
+       // Create color attachment view
+       {
+               const VkImageViewCreateInfo colorAttachmentViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,                       // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkImageViewCreateFlags               flags;
+                       *m_colorImage,                                                                          // VkImage                                              image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                          // VkImageViewType                              viewType;
+                       m_colorFormat,                                                                          // VkFormat                                             format;
+                       componentMappingRGBA,                                                           // VkChannelMapping                             channels;
+                       { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },          // VkImageSubresourceRange              subresourceRange;
+               };
+
+               m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+       }
+
+       // Create render pass
+       {
+               const VkAttachmentDescription colorAttachmentDescription =
+               {
+                       0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
+                       m_colorFormat,                                                                          // 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 VkAttachmentDescription attachments[1] =
+               {
+                       colorAttachmentDescription
+               };
+
+               const VkAttachmentReference colorAttachmentReference =
+               {
+                       0u,                                                                                                     // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
+               };
+               
+               const VkAttachmentReference depthAttachmentReference =
+               {
+                       VK_ATTACHMENT_UNUSED,                                                           // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_UNDEFINED                                                       // 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;
+                       &colorAttachmentReference,                                                      // const VkAttachmentReference*         pColorAttachments;
+                       DE_NULL,                                                                                        // const VkAttachmentReference*         pResolveAttachments;
+                       &depthAttachmentReference,                                                      // 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;
+                       attachments,                                                                            // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               const VkImageView attachmentBindInfos[1] =
+               {
+                 *m_colorAttachmentView
+               };
+
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags             flags;
+                       *m_renderPass,                                                                          // VkRenderPass                                 renderPass;
+                       1u,                                                                                                     // deUint32                                             attachmentCount;
+                       attachmentBindInfos,                                                            // const VkImageView*                   pAttachments;
+                       (deUint32)m_renderSize.x(),                                                     // deUint32                                             width;
+                       (deUint32)m_renderSize.y(),                                                     // deUint32                                             height;
+                       1u                                                                                                      // deUint32                                             layers;
+               };
+
+               m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create pipeline layout
+       {
+               // create push constant range
+               VkPushConstantRange     pushConstantRanges[MAX_RANGE_COUNT];
+               for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+               {
+                       pushConstantRanges[rangeNdx].stageFlags = m_pushConstantRange[rangeNdx].range.shaderStage;
+                       pushConstantRanges[rangeNdx].offset             = m_pushConstantRange[rangeNdx].range.offset;
+                       pushConstantRanges[rangeNdx].size               = m_pushConstantRange[rangeNdx].range.size;
+               }
+               
+               // create descriptor set layout
+               m_descriptorSetLayout = DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT).build(vk, vkDevice);
+               
+               // create descriptor pool
+               m_descriptorPool = DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u).build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+               
+               // create uniform buffer
+               const VkBufferCreateInfo uniformBufferCreateInfo =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                           // VkStructureType              sType;
+                       DE_NULL,                                                                                                        // const void*                  pNext;
+                       16u,                                                                                                            // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,                                                     // VkBufferUsageFlags   usage;
+                       0u,                                                                                                                     // VkBufferCreateFlags  flags;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                                                     // deUint32                             queueFamilyCount;
+                       &queueFamilyIndex                                                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+               
+               m_uniformBuffer                 = createBuffer(vk, vkDevice, &uniformBufferCreateInfo);
+               m_uniformBufferAlloc    = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_uniformBuffer), MemoryRequirement::HostVisible);
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferAlloc->getMemory(), m_uniformBufferAlloc->getOffset()));
+               
+               tcu::Vec4       value   = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+               deMemcpy(m_uniformBufferAlloc->getHostPtr(), &value, 16u);
+               flushMappedMemoryRange(vk, vkDevice, m_uniformBufferAlloc->getMemory(), m_uniformBufferAlloc->getOffset(), 16u);
+               
+               // create and update descriptor set
+               const VkDescriptorSetAllocateInfo allocInfo =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,                         // VkStructureType                             sType;
+                       DE_NULL,                                                                                                        // const void*                                 pNext;
+                       *m_descriptorPool,                                                                                      // VkDescriptorPool                            descriptorPool;
+                       1u,                                                                                                                     // uint32_t                                    setLayoutCount;
+                       &(*m_descriptorSetLayout),                                                                      // const VkDescriptorSetLayout*                pSetLayouts;
+               };
+               m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+               
+               const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*m_uniformBuffer, (VkDeviceSize)0u, (VkDeviceSize)16u);
+               
+               DescriptorSetUpdateBuilder()
+                       .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorInfo)
+                       .update(vk, vkDevice);
+               
+               // create pipeline layout
+               const VkPipelineLayoutCreateInfo        pipelineLayoutParams    =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkPipelineLayoutCreateFlags  flags;
+                       1u,                                                                                                     // deUint32                                             descriptorSetCount;
+                       &(*m_descriptorSetLayout),                                                      // const VkDescriptorSetLayout* pSetLayouts;
+                       m_rangeCount,                                                                           // deUint32                                             pushConstantRangeCount;
+                       pushConstantRanges                                                                      // const VkPushConstantRange*   pPushConstantRanges;
+               };
+               
+               m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       // Create shaders
+       {
+               for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+               {
+                       if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_GEOMETRY_BIT)
+                       {
+                               m_shaderFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
+                       }
+                       if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+                       {
+                               m_shaderFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+                       }
+                       if (m_pushConstantRange[rangeNdx].range.shaderStage & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+                       {
+                               m_shaderFlags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+                       }
+               }
+               
+               VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
+               
+               createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_vert", VK_SHADER_STAGE_VERTEX_BIT , &m_vertexShaderModule);
+               if (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+               {
+                       if (features.tessellationShader == VK_FALSE)
+                       {
+                               TCU_THROW(NotSupportedError, "Tessellation Not Supported");
+                       }
+                       createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_tesc", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, &m_tessControlShaderModule);
+                       createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_tese", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, &m_tessEvaluationShaderModule);
+               }
+               if (m_shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
+               {
+                       if (features.geometryShader == VK_FALSE)
+                       {
+                               TCU_THROW(NotSupportedError, "Geometry Not Supported");
+                       }
+                       createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_geom", VK_SHADER_STAGE_GEOMETRY_BIT, &m_geometryShaderModule);
+               }
+               createShaderStage(vk, vkDevice, m_context.getBinaryCollection(), "color_frag", VK_SHADER_STAGE_FRAGMENT_BIT, &m_fragmentShaderModule);
+       }
+
+       // Create pipeline
+       {
+               const VkVertexInputBindingDescription vertexInputBindingDescription =
+               {
+                       0u,                                                                             // deUint32                                     binding;
+                       sizeof(Vertex4RGBA),                                    // deUint32                                     strideInBytes;
+                       VK_VERTEX_INPUT_RATE_VERTEX                             // VkVertexInputStepRate        stepRate;
+               };
+
+               const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
+               {
+                       {
+                               0u,                                                                     // deUint32     location;
+                               0u,                                                                     // deUint32     binding;
+                               VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                               0u                                                                      // deUint32     offsetInBytes;
+                       }
+               };
+
+               const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // vkPipelineVertexInputStateCreateFlags        flags;
+                       1u,                                                                                                                             // deUint32                                                                     bindingCount;
+                       &vertexInputBindingDescription,                                                                 // const VkVertexInputBindingDescription*       pVertexBindingDescriptions;
+                       1u,                                                                                                                             // deUint32                                                                     attributeCount;
+                       vertexInputAttributeDescriptions                                                                // const VkVertexInputAttributeDescription*     pVertexAttributeDescriptions;
+               };
+
+               const VkPrimitiveTopology topology = (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+               const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       (VkPipelineInputAssemblyStateCreateFlags)0u,                                    // VkPipelineInputAssemblyStateCreateFlags      flags;
+                       topology,                                                                                                               // VkPrimitiveTopology                                          topology;
+                       false                                                                                                                   // VkBool32                                                                     primitiveRestartEnable;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        originX;
+                       0.0f,                                           // float        originY;
+                       (float)m_renderSize.x(),        // float        width;
+                       (float)m_renderSize.y(),        // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+               const VkPipelineViewportStateCreateInfo viewportStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                  // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                                // const void*                                                  pNext;
+                       (VkPipelineViewportStateCreateFlags)0u,                                                 // VkPipelineViewportStateCreateFlags   flags;
+                       1u,                                                                                                                             // deUint32                                                             viewportCount;
+                       &viewport,                                                                                                              // const VkViewport*                                    pViewports;
+                       1u,                                                                                                                             // deUint32                                                             scissorCount;
+                       &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;
+                       VK_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,                                                                                    // VkBlendFactor                        srcColorBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                   // VkBlendFactor                        dstColorBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                // VkBlendOp                            colorBlendOp;
+                       VK_BLEND_FACTOR_ONE,                                                                                    // VkBlendFactor                        srcAlphaBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                   // VkBlendFactor                        dstAlphaBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                // VkBlendOp                            alphaBlendOp;
+                       VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                   // VkColorComponentFlags        colorWriteMask;
+                               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;
+                       0,                                                                                                                      // 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 VkPipelineMultisampleStateCreateInfo      multisampleStateParams  =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                          // VkSampleCountFlagBits                                        rasterizationSamples;
+                       false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                           // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+                       false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+                       false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+               };
+               
+               const VkPipelineDynamicStateCreateInfo dynamicStateParams               =
+               {
+                       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;
+               };
+               
+               VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineDepthStencilStateCreateFlags       flags;
+                       false,                                                                                                          // VkBool32                                                                     depthTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     depthWriteEnable;
+                       VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                                                          depthCompareOp;
+                       false,                                                                                                          // VkBool32                                                                     depthBoundsTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     stencilTestEnable;
+                       // VkStencilOpState     front;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilFailOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilPassOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilDepthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  stencilCompareOp;
+                               0u,                                             // deUint32             stencilCompareMask;
+                               0u,                                             // deUint32             stencilWriteMask;
+                               0u,                                             // deUint32             stencilReference;
+                       },
+                       // VkStencilOpState     back;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilFailOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilPassOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  stencilDepthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  stencilCompareOp;
+                               0u,                                             // deUint32             stencilCompareMask;
+                               0u,                                             // deUint32             stencilWriteMask;
+                               0u,                                             // deUint32             stencilReference;
+                       },
+                       -1.0f,                                                                                                          // float                        minDepthBounds;
+                       +1.0f,                                                                                                          // float                        maxDepthBounds;
+               };
+
+               const VkPipelineTessellationStateCreateInfo tessellationStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,              // VkStructureType                             sType;
+                       DE_NULL,                                                                                                                // const void*                                 pNext;
+                       0u,                                                                                                                             // VkPipelineTesselationStateCreateFlags       flags;
+                       3u,                                                                                                                             // uint32_t                                    patchControlPoints;
+               };
+
+               const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       0u,                                                                                                     // VkPipelineCreateFlags                                                        flags;
+                       (deUint32)m_shaderStage.size(),                                         // deUint32                                                                                     stageCount;
+                       &m_shaderStage[0],                                                                      // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       (m_shaderFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? &tessellationStateParams: DE_NULL),                 // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &depthStencilStateParams,                                                       // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateParams,                                                            // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *m_pipelineLayout,                                                                      // VkPipelineLayout                                                                     layout;
+                       *m_renderPass,                                                                          // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               m_graphicsPipelines = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create vertex buffer
+       {
+               m_vertices                      = createQuad(1.0f);
+               
+               const VkBufferCreateInfo vertexBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                           // VkStructureType              sType;
+                       DE_NULL,                                                                                                        // const void*                  pNext;
+                       0u,                                                                                                                     // VkBufferCreateFlags  flags;
+                       (VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()),        // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                                                      // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                                                     // deUint32                             queueFamilyCount;
+                       &queueFamilyIndex                                                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+               
+               m_vertexBuffer          = createBuffer(vk, vkDevice, &vertexBufferParams);
+               m_vertexBufferAlloc     = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+               // Load vertices into vertex buffer
+               deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+               flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,     // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,           // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex                                                        // deUint32                             queueFamilyIndex;
+               };
+               m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *m_cmdPool,                                                                             // VkCommandPool                        commandPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCommandBufferLevel         level;
+                       1u                                                                                              // deUint32                                     bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCommandBufferUsageFlags            flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       false,                                                                                  // VkBool32                                                     occlusionQueryEnable;
+                       0u,                                                                                             // VkQueryControlFlags                          queryFlags;
+                       0u                                                                                              // VkQueryPipelineStatisticFlags        pipelineStatistics;
+               };
+
+               const VkClearValue attachmentClearValues[] =
+               {
+                       defaultClearValue(m_colorFormat)
+               };
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *m_renderPass,                                                                                  // VkRenderPass                 renderPass;
+                       *m_framebuffer,                                                                                 // VkFramebuffer                framebuffer;
+                       { { 0, 0 } , { m_renderSize.x(), m_renderSize.y() } },  // VkRect2D                             renderArea;
+                       1,                                                                                                              // deUint32                             clearValueCount;
+                       attachmentClearValues                                                                   // const VkClearValue*  pClearValues;
+               };
+
+               m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+               VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               // update push constant
+               std::vector<tcu::Vec4> color(8, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+               std::vector<tcu::Vec4> allOnes(8, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+               
+               const deUint32  kind    = 2u;
+               const void*     value   = DE_NULL;
+               for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+               {
+                       value = (m_pushConstantRange[rangeNdx].range.size == 4u) ? (void*)(&kind) : (void*)(&color[0]);
+                               
+                       vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[rangeNdx].range.shaderStage, m_pushConstantRange[rangeNdx].range.offset, m_pushConstantRange[rangeNdx].range.size, value);
+                       
+                       if (m_pushConstantRange[rangeNdx].update.size < m_pushConstantRange[rangeNdx].range.size)
+                       {
+                               value = (void*)(&allOnes[0]);
+                               vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[rangeNdx].range.shaderStage, m_pushConstantRange[rangeNdx].update.offset, m_pushConstantRange[rangeNdx].update.size, value);
+                       }
+               }
+               
+               // draw quad
+               const VkDeviceSize      triangleOffset  = (m_vertices.size() / TRIANGLE_COUNT) * sizeof(Vertex4RGBA);
+               for (int triangleNdx = 0; triangleNdx < TRIANGLE_COUNT; triangleNdx++)
+               {
+                       VkDeviceSize vertexBufferOffset = triangleOffset * triangleNdx;
+                       
+                       if (m_multipleUpdate)
+                       {
+                               vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange[0].range.shaderStage, m_pushConstantRange[0].range.offset, m_pushConstantRange[0].range.size, &triangleNdx);
+                       }
+
+                       vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines);
+                       vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+                       vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &(*m_descriptorSet), 0, DE_NULL);
+                       
+                       vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / TRIANGLE_COUNT), 1, 0, 0);
+               }
+
+               vk.cmdEndRenderPass(*m_cmdBuffer);
+               VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               m_fence = createFence(vk, vkDevice, &fenceParams);
+       }
+}
+
+PushConstantGraphicsTestInstance::~PushConstantGraphicsTestInstance (void)
+{
+}
+
+tcu::TestStatus PushConstantGraphicsTestInstance::iterate (void)
+{
+       const DeviceInterface&          vk                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice        = m_context.getDevice();
+       const VkQueue                           queue           = m_context.getUniversalQueue();
+       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;
+               &m_cmdBuffer.get(),                             // const VkCommandBuffer*       pCommandBuffers;
+               0u,                                                             // deUint32                                     signalSemaphoreCount;
+               DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+       };
+
+       VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+       VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+       return verifyImage();
+}
+
+tcu::TestStatus PushConstantGraphicsTestInstance::verifyImage (void)
+{
+       const tcu::TextureFormat        tcuColorFormat  = mapVkFormat(m_colorFormat);
+       const tcu::TextureFormat        tcuDepthFormat  = tcu::TextureFormat();
+       const ColorVertexShader         vertexShader;
+       const ColorFragmentShader       fragmentShader  (tcuColorFormat, tcuDepthFormat);
+       const rr::Program                       program                 (&vertexShader, &fragmentShader);
+       ReferenceRenderer                       refRenderer             (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+       bool                                            compareOk               = false;
+
+       // Render reference image
+       {
+               if (m_shaderFlags & VK_SHADER_STAGE_GEOMETRY_BIT)
+               {
+                       m_vertices = createQuad(0.5f);
+               }
+               
+               for (size_t rangeNdx = 0; rangeNdx < m_rangeCount; rangeNdx++)
+               {
+                       if (m_pushConstantRange[rangeNdx].update.size < m_pushConstantRange[rangeNdx].range.size)
+                       {
+                               for (size_t vertexNdx = 0; vertexNdx < m_vertices.size(); vertexNdx++)
+                               {
+                                       m_vertices[vertexNdx].color.xyzw() = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
+                               }
+                       }
+               }
+               
+               if (m_multipleUpdate)
+               {
+                       for (size_t vertexNdx = 0; vertexNdx < 3; vertexNdx++)
+                       {
+                               m_vertices[vertexNdx].color.xyz() = tcu::Vec3(0.0f, 1.0f, 0.0f);
+                       }
+                       for (size_t vertexNdx = 3; vertexNdx < m_vertices.size(); vertexNdx++)
+                       {
+                               m_vertices[vertexNdx].color.xyz() = tcu::Vec3(0.0f, 0.0f, 1.0f);
+                       }
+               }
+               
+               for (int triangleNdx = 0; triangleNdx < TRIANGLE_COUNT; triangleNdx++)
+               {
+                       rr::RenderState renderState(refRenderer.getViewportState());
+                       
+                       refRenderer.draw(renderState,
+                                                        rr::PRIMITIVETYPE_TRIANGLES,
+                                                        std::vector<Vertex4RGBA>(m_vertices.begin() + triangleNdx * 3,
+                                                                                                         m_vertices.begin() + (triangleNdx + 1) * 3));
+               }
+       }
+
+       // Compare result with reference image
+       {
+               const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
+               const VkDevice                                  vkDevice                        = m_context.getDevice();
+               const VkQueue                                   queue                           = m_context.getUniversalQueue();
+               const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+               SimpleAllocator                                 allocator                       (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+               de::MovePtr<tcu::TextureLevel>  result                          = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
+
+               compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+                                                                                                                         "IntImageCompare",
+                                                                                                                         "Image comparison",
+                                                                                                                         refRenderer.getAccess(),
+                                                                                                                         result->getAccess(),
+                                                                                                                         tcu::UVec4(2, 2, 2, 2),
+                                                                                                                         tcu::IVec3(1, 1, 0),
+                                                                                                                         true,
+                                                                                                                         tcu::COMPARE_LOG_RESULT);
+       }
+
+       if (compareOk)
+               return tcu::TestStatus::pass("Result image matches reference");
+       else
+               return tcu::TestStatus::fail("Image mismatch");
+}
+
+class PushConstantComputeTest : public vkt::TestCase
+{
+public:
+                                                       PushConstantComputeTest         (tcu::TestContext&              testContext,
+                                                                                                                const std::string&             name,
+                                                                                                                const std::string&             description,
+                                                                                                                const PushConstantData pushConstantRange);
+       virtual                                 ~PushConstantComputeTest        (void);
+       virtual void                    initPrograms                            (SourceCollections& sourceCollections) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+       
+private:
+       const PushConstantData  m_pushConstantRange;
+};
+
+class PushConstantComputeTestInstance : public vkt::TestInstance
+{
+public:
+                                                       PushConstantComputeTestInstance         (Context&                               context,
+                                                                                                                                const PushConstantData pushConstantRange);
+       virtual                                 ~PushConstantComputeTestInstance        (void);
+       virtual tcu::TestStatus iterate                                                         (void);
+
+private:
+       const PushConstantData                  m_pushConstantRange;
+       
+       Move<VkBuffer>                                  m_outBuffer;
+       de::MovePtr<Allocation>                 m_outBufferAlloc;
+       Move<VkDescriptorPool>                  m_descriptorPool;
+       Move<VkDescriptorSetLayout>             m_descriptorSetLayout;
+       Move<VkDescriptorSet>                   m_descriptorSet;
+       
+       Move<VkPipelineLayout>                  m_pipelineLayout;
+       Move<VkPipeline>                                m_computePipelines;
+       
+       Move<VkShaderModule>                    m_computeShaderModule;
+       
+       Move<VkCommandPool>                             m_cmdPool;
+       Move<VkCommandBuffer>                   m_cmdBuffer;
+
+       Move<VkFence>                                   m_fence;
+};
+
+PushConstantComputeTest::PushConstantComputeTest (tcu::TestContext&                    testContext,
+                                                                                                 const std::string&            name,
+                                                                                                 const std::string&            description,
+                                                                                                 const PushConstantData        pushConstantRange)
+       : vkt::TestCase                 (testContext, name, description)
+       , m_pushConstantRange   (pushConstantRange)
+{
+}
+
+PushConstantComputeTest::~PushConstantComputeTest (void)
+{
+}
+
+TestInstance* PushConstantComputeTest::createInstance (Context& context) const
+{
+       return new PushConstantComputeTestInstance(context, m_pushConstantRange);
+}
+
+void PushConstantComputeTest::initPrograms (SourceCollections& sourceCollections) const
+{
+       std::ostringstream      computeSrc;
+       
+       computeSrc << "#version 450\n"
+                          << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
+                          << "layout(std140, set = 0, binding = 0) writeonly buffer Output {\n"
+                          << "  vec4 elements[];\n"
+                          << "} outData;\n"
+                          << "layout(push_constant) uniform Material{\n"
+                          << "  vec4 element;\n"
+                          << "} matInst;\n"
+                          << "void main (void)\n"
+                          << "{\n"
+                          << "  outData.elements[gl_GlobalInvocationID.x] = matInst.element;\n"
+                          << "}\n";
+                   
+       sourceCollections.glslSources.add("compute") << glu::ComputeSource(computeSrc.str());
+}
+
+PushConstantComputeTestInstance::PushConstantComputeTestInstance (Context&                                     context,
+                                                                                                                                 const PushConstantData        pushConstantRange)
+       : vkt::TestInstance             (context)
+       , m_pushConstantRange   (pushConstantRange)
+{
+       const DeviceInterface&          vk                                      = context.getDeviceInterface();
+       const VkDevice                          vkDevice                        = context.getDevice();
+       const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                         memAlloc                        (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+
+       // Create pipeline layout
+       {
+               // create push constant range
+               VkPushConstantRange     pushConstantRanges;
+               pushConstantRanges.stageFlags   = m_pushConstantRange.range.shaderStage;
+               pushConstantRanges.offset               = m_pushConstantRange.range.offset;
+               pushConstantRanges.size                 = m_pushConstantRange.range.size;
+               
+               // create descriptor set layout
+               m_descriptorSetLayout = DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT).build(vk, vkDevice);
+               
+               // create descriptor pool
+               m_descriptorPool = DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u).build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+               
+               // create uniform buffer
+               const VkDeviceSize                      bufferSize                      = sizeof(tcu::Vec4) * 8;
+               const VkBufferCreateInfo        bufferCreateInfo        =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                           // VkStructureType              sType;
+                       DE_NULL,                                                                                                        // const void*                  pNext;
+                       bufferSize,                                                                                                     // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,                                                     // VkBufferUsageFlags   usage;
+                       0u,                                                                                                                     // VkBufferCreateFlags  flags;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                                                     // deUint32                             queueFamilyCount;
+                       &queueFamilyIndex                                                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+               
+               m_outBuffer                     = createBuffer(vk, vkDevice, &bufferCreateInfo);
+               m_outBufferAlloc        = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outBuffer), MemoryRequirement::HostVisible);
+               VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
+               
+               // create and update descriptor set
+               const VkDescriptorSetAllocateInfo allocInfo =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,                         // VkStructureType                             sType;
+                       DE_NULL,                                                                                                        // const void*                                 pNext;
+                       *m_descriptorPool,                                                                                      // VkDescriptorPool                            descriptorPool;
+                       1u,                                                                                                                     // uint32_t                                    setLayoutCount;
+                       &(*m_descriptorSetLayout),                                                                      // const VkDescriptorSetLayout*                pSetLayouts;
+               };
+               m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+               
+               const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*m_outBuffer, (VkDeviceSize)0u, bufferSize);
+               
+               DescriptorSetUpdateBuilder()
+                       .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
+                       .update(vk, vkDevice);
+               
+               // create pipeline layout
+               const VkPipelineLayoutCreateInfo        pipelineLayoutParams    =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkPipelineLayoutCreateFlags  flags;
+                       1u,                                                                                                     // deUint32                                             descriptorSetCount;
+                       &(*m_descriptorSetLayout),                                                      // const VkDescriptorSetLayout* pSetLayouts;
+                       1u,                                                                                                     // deUint32                                             pushConstantRangeCount;
+                       &pushConstantRanges                                                                     // const VkPushConstantRange*   pPushConstantRanges;
+               };
+               
+               m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+       
+       // create pipeline
+       {
+               m_computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0);
+               
+               const VkPipelineShaderStageCreateInfo   stageCreateInfo =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                // const void*                                                  pNext;
+                       0u,                                                                                                             // VkPipelineShaderStageCreateFlags             flags;
+                       VK_SHADER_STAGE_COMPUTE_BIT,                                                    // VkShaderStageFlagBits                                stage;
+                       *m_computeShaderModule,                                                                 // VkShaderModule                                               module;
+                       "main",                                                                                                 // const char*                                                  pName;
+                       DE_NULL                                                                                                 // const VkSpecializationInfo*                  pSpecializationInfo;
+               };
+               
+               const VkComputePipelineCreateInfo               createInfo      =
+               {
+                       VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,                 // VkStructureType                             sType;
+                       DE_NULL,                                                                                                // const void*                                 pNext;
+                       0u,                                                                                                             // VkPipelineCreateFlags                       flags;
+                       stageCreateInfo,                                                                                // VkPipelineShaderStageCreateInfo             stage;
+                       *m_pipelineLayout,                                                                              // VkPipelineLayout                            layout;
+                       (VkPipeline)0,                                                                                  // VkPipeline                                  basePipelineHandle;
+                       0u,                                                                                                             // int32_t                                     basePipelineIndex;
+               };
+
+               m_computePipelines = createComputePipeline(vk, vkDevice, (vk::VkPipelineCache)0u, &createInfo);
+       }
+       
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,             // VkStructureType              sType;
+                       DE_NULL,                                                                                // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                   // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex                                                                // deUint32                             queueFamilyIndex;
+               };
+               m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *m_cmdPool,                                                                             // VkCommandPool                        commandPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCommandBufferLevel         level;
+                       1u                                                                                              // deUint32                                     bufferCount;
+               };
+               
+               m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCommandBufferUsageFlags            flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       false,                                                                                  // VkBool32                                                     occlusionQueryEnable;
+                       0u,                                                                                             // VkQueryControlFlags                          queryFlags;
+                       0u                                                                                              // VkQueryPipelineStatisticFlags        pipelineStatistics;
+               };
+               
+               VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+               
+               vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipelines);
+               vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0, 1, &(*m_descriptorSet), 0, DE_NULL);
+               
+               // update push constant
+               tcu::Vec4       value   = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+               vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, m_pushConstantRange.range.shaderStage, m_pushConstantRange.range.offset, m_pushConstantRange.range.size, &value);
+               
+               vk.cmdDispatch(*m_cmdBuffer, 8, 1, 1);
+               
+               VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               m_fence = createFence(vk, vkDevice, &fenceParams);
+       }
+}
+
+PushConstantComputeTestInstance::~PushConstantComputeTestInstance (void)
+{
+}
+
+tcu::TestStatus PushConstantComputeTestInstance::iterate (void)
+{
+       const DeviceInterface&          vk                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice        = m_context.getDevice();
+       const VkQueue                           queue           = m_context.getUniversalQueue();
+       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;
+               &m_cmdBuffer.get(),                             // const VkCommandBuffer*       pCommandBuffers;
+               0u,                                                             // deUint32                                     signalSemaphoreCount;
+               DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+       };
+
+       VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+       VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+       // verify result
+       std::vector<tcu::Vec4>  expectValue(8, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+       if (deMemCmp((void*)(&expectValue[0]), m_outBufferAlloc->getHostPtr(), (size_t)(sizeof(tcu::Vec4) * 8)))
+       {
+               return tcu::TestStatus::fail("Image mismatch");
+       }
+       return tcu::TestStatus::pass("result image matches with reference");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createPushConstantTests (tcu::TestContext& testCtx)
+{
+       static const struct
+       {
+               const char*                     name;
+               const char*                     description;
+               deUint32                        count;
+               PushConstantData        range[MAX_RANGE_COUNT];
+               deBool                          hasMultipleUpdates;
+       } graphicsParams[] =
+       {
+               // test range size from minimum valid size to maximum
+               {
+                       "range_size_4",
+                       "test range size is 4 bytes(minimum valid size)",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 } , { 0, 4 } } },
+                       false
+               },
+               {
+                       "range_size_16",
+                       "test range size is 16 bytes, and together with a normal uniform",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } } },
+                       false
+               },
+               {
+                       "range_size_128",
+                       "test range size is 128 bytes(maximum valid size)",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 128 }, { 0, 128 } } },
+                       false
+               },
+               // test range count, including all valid shader stage in graphics pipeline, and also multiple shader stages share one single range
+               {
+                       "count_2_shader_VF",
+                       "test range count is 2, use vertex and fragment shaders",
+                       2u,
+                       {
+                               { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+                               { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+                       },
+                       false
+               },
+               {
+                       "count_3shader_VGF",
+                       "test range count is 3, use vertex, geometry and fragment shaders",
+                       3u,
+                       {
+                               { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+                               { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+                               { { VK_SHADER_STAGE_GEOMETRY_BIT, 20, 4 }, { 20, 4 } },
+                       },
+                       false
+               },
+               {
+                       "count_5_shader_VTGF",
+                       "test range count is 5, use vertex, tessellation, geometry and fragment shaders",
+                       5u,
+                       {
+                               { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 0, 16 } },
+                               { { VK_SHADER_STAGE_FRAGMENT_BIT, 16, 4 }, { 16, 4 } },
+                               { { VK_SHADER_STAGE_GEOMETRY_BIT, 20, 4 }, { 20, 4 } },
+                               { { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 24, 4 }, { 24, 4 } },
+                               { { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 28, 16 }, { 28, 16 } },
+                       },
+                       false
+               },
+               {
+                       "count_1_shader_VF",
+                       "test range count is 1, vertex and fragment shaders share one range",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4 }, { 0, 4 } } },
+                       false
+               },
+               // test data partial update and multiple times update
+               {
+                       "data_update_partial_1",
+                       "test partial update of the values",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, { 4, 8 } } },
+                       false
+               },
+               {
+                       "data_update_partial_2",
+                       "test partial update of the values",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 40 }, { 24, 16 } } },
+                       false
+               },
+               {
+                       "data_update_multiple",
+                       "test multiple times update of the values",
+                       1u,
+                       { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 }, { 0, 4 } } },
+                       true
+               },
+       };
+       
+       static const struct
+       {
+               const char*                     name;
+               const char*                     description;
+               PushConstantData        range;
+       } computeParams[] =
+       {
+               {
+                       "simple_test",
+                       "test compute pipeline",
+                       { { VK_SHADER_STAGE_COMPUTE_BIT, 0, 16 }, { 0, 16 } },
+               },
+       };
+
+       de::MovePtr<tcu::TestCaseGroup> pushConstantTests       (new tcu::TestCaseGroup(testCtx, "push_constant", "PushConstant tests"));
+       
+       de::MovePtr<tcu::TestCaseGroup> graphicsTests   (new tcu::TestCaseGroup(testCtx, "graphics_pipeline", "graphics pipeline"));
+       for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(graphicsParams); ndx++)
+       {
+               graphicsTests->addChild(new PushConstantGraphicsTest(testCtx, graphicsParams[ndx].name, graphicsParams[ndx].description, graphicsParams[ndx].count, graphicsParams[ndx].range, graphicsParams[ndx].hasMultipleUpdates));
+       }
+       pushConstantTests->addChild(graphicsTests.release());
+       
+       de::MovePtr<tcu::TestCaseGroup> computeTests    (new tcu::TestCaseGroup(testCtx, "compute_pipeline", "compute pipeline"));
+       computeTests->addChild(new PushConstantComputeTest(testCtx, computeParams[0].name, computeParams[0].description, computeParams[0].range));
+       pushConstantTests->addChild(computeTests.release());
+       
+       return pushConstantTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelinePushConstantTests.hpp
new file mode 100644 (file)
index 0000000..e4f7c14
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEPUSHCONSTANTTESTS_HPP
+#define _VKTPIPELINEPUSHCONSTANTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 ARM Limited.
+ *
+ * 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 PushConstant Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createPushConstantTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEPUSHCONSTANTTESTS_HPP
index a32196b..68376f9 100644 (file)
@@ -256,6 +256,12 @@ ReferenceRenderer::~ReferenceRenderer (void)
        delete m_renderTarget;
 }
 
+void ReferenceRenderer::colorClear(const tcu::Vec4& color)
+{
+       tcu::clear(m_colorBuffer.getAccess(), color);
+       tcu::clear(m_resolveColorBuffer.getAccess(), color);
+}
+
 void ReferenceRenderer::draw (const rr::RenderState&                   renderState,
                                                          const rr::PrimitiveType                       primitive,
                                                          const std::vector<Vertex4RGBA>&       vertexBuffer)
index 519b8dc..41f514a 100644 (file)
@@ -255,11 +255,11 @@ public:
                        {
                                const tcu::Vec4 vtxTexCoord     = rr::readVarying<float>(packet, context, 1, fragNdx);
                                const tcu::Vec4 texColor        = sampleTexture(m_texture, m_sampler, vtxTexCoord, m_lod);
-                               const tcu::Vec4 normColor       = texColor * m_textureFormatInfo.lookupScale + m_textureFormatInfo.lookupBias;
+                               const tcu::Vec4 swizColor       = swizzle(texColor, m_swizzle);
+                               const tcu::Vec4 normColor       = swizColor * m_textureFormatInfo.lookupScale + m_textureFormatInfo.lookupBias;
                                const tcu::Vec4 color           = (normColor - m_colorFormatInfo.lookupBias) / m_colorFormatInfo.lookupScale;
-                               const tcu::Vec4 outColor        = swizzle(color, m_swizzle);
 
-                               rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, outColor);
+                               rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
                        }
                }
        }
@@ -306,6 +306,8 @@ public:
 
        virtual                                         ~ReferenceRenderer              (void);
 
+       void                                            colorClear                              (const tcu::Vec4& color);
+
        void                                            draw                                    (const rr::RenderState&                         renderState,
                                                                                                                 const rr::PrimitiveType                        primitive,
                                                                                                                 const std::vector<Vertex4RGBA>&        vertexBuffer);
index 51bef25..75ba321 100644 (file)
@@ -290,7 +290,14 @@ tcu::IVec2 SamplerTest::getRenderSize (VkImageViewType viewType) const
 
 std::vector<Vertex4Tex4> SamplerTest::createVertices (void) const
 {
-       return createTestQuadMosaic(m_imageViewType);
+       std::vector<Vertex4Tex4> vertices = createTestQuadMosaic(m_imageViewType);
+       // Adjust texture coordinate to avoid doing NEAREST filtering exactly on texel boundaries.
+       // TODO: Would be nice to base this on number of texels and subtexel precision. But this
+       // seems to work.
+       for (unsigned int i = 0; i < vertices.size(); ++i) {
+               vertices[i].texCoord += tcu::Vec4(0.001f, 0.001f, 0.001f, 0.0f);
+       }
+       return vertices;
 }
 
 VkSamplerCreateInfo SamplerTest::getSamplerCreateInfo (void) const
@@ -443,6 +450,8 @@ VkSamplerCreateInfo SamplerMinFilterTest::getSamplerCreateInfo (void) const
 {
        VkSamplerCreateInfo samplerParams = SamplerTest::getSamplerCreateInfo();
        samplerParams.minFilter = m_minFilter;
+       // set minLod to epsilon, to force use of the minFilter
+       samplerParams.minLod = 0.01f;
 
        return samplerParams;
 }
@@ -568,7 +577,8 @@ MovePtr<tcu::TestCaseGroup> createSamplerMagFilterTests (tcu::TestContext& testC
 {
        MovePtr<tcu::TestCaseGroup> samplerMagFilterTests (new tcu::TestCaseGroup(testCtx, "mag_filter", "Tests for magnification filter"));
 
-       samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "linear", "Magnifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
+       if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+               samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "linear", "Magnifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
        samplerMagFilterTests->addChild(new SamplerMagFilterTest(testCtx, "nearest", "Magnifies image using VK_TEX_FILTER_NEAREST", imageViewType, imageFormat, VK_FILTER_NEAREST));
 
        return samplerMagFilterTests;
@@ -578,7 +588,8 @@ MovePtr<tcu::TestCaseGroup> createSamplerMinFilterTests (tcu::TestContext& testC
 {
        MovePtr<tcu::TestCaseGroup> samplerMinFilterTests (new tcu::TestCaseGroup(testCtx, "min_filter", "Tests for minification filter"));
 
-       samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "linear", "Minifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
+       if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+               samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "linear", "Minifies image using VK_TEX_FILTER_LINEAR", imageViewType, imageFormat, VK_FILTER_LINEAR));
        samplerMinFilterTests->addChild(new SamplerMinFilterTest(testCtx, "nearest", "Minifies image using VK_TEX_FILTER_NEAREST", imageViewType, imageFormat, VK_FILTER_NEAREST));
 
        return samplerMinFilterTests;
@@ -629,9 +640,12 @@ MovePtr<tcu::TestCaseGroup> createSamplerMipmapTests (tcu::TestContext& testCtx,
        samplerMipmapTests->addChild(mipmapNearestTests.release());
 
        // Mipmap mode: linear
-       MovePtr<tcu::TestCaseGroup> mipmapLinearTests (new tcu::TestCaseGroup(testCtx, "linear", "Uses VK_TEX_MIPMAP_MODE_LINEAR"));
-       mipmapLinearTests->addChild(createSamplerLodTests(testCtx, imageViewType, imageFormat, VK_SAMPLER_MIPMAP_MODE_LINEAR).release());
-       samplerMipmapTests->addChild(mipmapLinearTests.release());
+       if (isCompressedFormat(imageFormat) || (!isIntFormat(imageFormat) && !isUintFormat(imageFormat)))
+       {
+               MovePtr<tcu::TestCaseGroup> mipmapLinearTests(new tcu::TestCaseGroup(testCtx, "linear", "Uses VK_TEX_MIPMAP_MODE_LINEAR"));
+               mipmapLinearTests->addChild(createSamplerLodTests(testCtx, imageViewType, imageFormat, VK_SAMPLER_MIPMAP_MODE_LINEAR).release());
+               samplerMipmapTests->addChild(mipmapLinearTests.release());
+       }
 
        return samplerMipmapTests;
 }
index 22935ce..1cba488 100644 (file)
 #include "vktPipelineBlendTests.hpp"
 #include "vktPipelineDepthTests.hpp"
 #include "vktPipelineImageTests.hpp"
+#include "vktPipelineInputAssemblyTests.hpp"
 #include "vktPipelineSamplerTests.hpp"
 #include "vktPipelineImageViewTests.hpp"
+#include "vktPipelinePushConstantTests.hpp"
+#include "vktPipelineMultisampleTests.hpp"
+#include "vktPipelineVertexInputTests.hpp"
 #include "deUniquePtr.hpp"
 
 namespace vkt
@@ -51,12 +55,16 @@ tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> pipelineTests (new tcu::TestCaseGroup(testCtx, "pipeline", "Pipeline Tests"));
 
-       pipelineTests->addChild(createStencilTests(testCtx));
-       pipelineTests->addChild(createBlendTests(testCtx));
-       pipelineTests->addChild(createDepthTests(testCtx));
-       pipelineTests->addChild(createImageTests(testCtx));
-       pipelineTests->addChild(createSamplerTests(testCtx));
-       pipelineTests->addChild(createImageViewTests(testCtx));
+       pipelineTests->addChild(createStencilTests              (testCtx));
+       pipelineTests->addChild(createBlendTests                (testCtx));
+       pipelineTests->addChild(createDepthTests                (testCtx));
+       pipelineTests->addChild(createImageTests                (testCtx));
+       pipelineTests->addChild(createSamplerTests              (testCtx));
+       pipelineTests->addChild(createImageViewTests    (testCtx));
+       pipelineTests->addChild(createPushConstantTests (testCtx));
+       pipelineTests->addChild(createMultisampleTests  (testCtx));
+       pipelineTests->addChild(createVertexInputTests  (testCtx));
+       pipelineTests->addChild(createInputAssemblyTests(testCtx));
 
        return pipelineTests.release();
 }
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.cpp
new file mode 100644 (file)
index 0000000..34db1fb
--- /dev/null
@@ -0,0 +1,1666 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Vertex Input Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineVertexInputTests.hpp"
+#include "vktPipelineCombinationsIterator.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuFloat.hpp"
+#include "tcuImageCompare.hpp"
+#include "deFloat16.h"
+#include "deMemory.h"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+bool isSupportedVertexFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
+{
+       VkFormatProperties  formatProps;
+       deMemset(&formatProps, 0, sizeof(VkFormatProperties));
+       instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
+
+       return (formatProps.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0u;
+}
+
+float getRepresentableDifferenceUnorm (VkFormat format)
+{
+       DE_ASSERT(isVertexFormatUnorm(format) || isVertexFormatSRGB(format));
+
+       return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8)) - 1);
+}
+
+float getRepresentableDifferenceSnorm (VkFormat format)
+{
+       DE_ASSERT(isVertexFormatSnorm(format));
+
+       return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8 - 1)) - 1);
+}
+
+class VertexInputTest : public vkt::TestCase
+{
+public:
+       enum GlslType
+       {
+               GLSL_TYPE_INT,
+               GLSL_TYPE_IVEC2,
+               GLSL_TYPE_IVEC3,
+               GLSL_TYPE_IVEC4,
+
+               GLSL_TYPE_UINT,
+               GLSL_TYPE_UVEC2,
+               GLSL_TYPE_UVEC3,
+               GLSL_TYPE_UVEC4,
+
+               GLSL_TYPE_FLOAT,
+               GLSL_TYPE_VEC2,
+               GLSL_TYPE_VEC3,
+               GLSL_TYPE_VEC4,
+               GLSL_TYPE_MAT2,
+               GLSL_TYPE_MAT3,
+               GLSL_TYPE_MAT4,
+
+               GLSL_TYPE_DOUBLE,
+               GLSL_TYPE_DVEC2,
+               GLSL_TYPE_DVEC3,
+               GLSL_TYPE_DVEC4,
+               GLSL_TYPE_DMAT2,
+               GLSL_TYPE_DMAT3,
+               GLSL_TYPE_DMAT4,
+
+               GLSL_TYPE_COUNT
+       };
+
+       enum GlslBasicType
+       {
+               GLSL_BASIC_TYPE_INT,
+               GLSL_BASIC_TYPE_UINT,
+               GLSL_BASIC_TYPE_FLOAT,
+               GLSL_BASIC_TYPE_DOUBLE
+       };
+
+       enum BindingMapping
+       {
+               BINDING_MAPPING_ONE_TO_ONE,     // Vertex input bindings will not contain data for more than one attribute.
+               BINDING_MAPPING_ONE_TO_MANY     // Vertex input bindings can contain data for more than one attribute.
+       };
+
+       struct AttributeInfo
+       {
+               GlslType                                glslType;
+               VkFormat                                vkType;
+               VkVertexInputRate               inputRate;
+       };
+
+       struct GlslTypeDescription
+       {
+               const char*             name;
+               int                             vertexInputComponentCount;
+               int                             vertexInputCount;
+               GlslBasicType   basicType;
+       };
+
+       static const GlslTypeDescription                s_glslTypeDescriptions[GLSL_TYPE_COUNT];
+
+                                                                                       VertexInputTest                         (tcu::TestContext&                                      testContext,
+                                                                                                                                                const std::string&                                     name,
+                                                                                                                                                const std::string&                                     description,
+                                                                                                                                                const std::vector<AttributeInfo>&      attributeInfos,
+                                                                                                                                                BindingMapping                                         bindingMapping);
+
+       virtual                                                                 ~VertexInputTest                        (void) {}
+       virtual void                                                    initPrograms                            (SourceCollections& programCollection) const;
+       virtual TestInstance*                                   createInstance                          (Context& context) const;
+       static bool                                                             isCompatibleType                        (VkFormat format, GlslType glslType);
+
+private:
+       std::string                                                             getGlslInputDeclarations        (void) const;
+       std::string                                                             getGlslVertexCheck                      (void) const;
+       std::string                                                             getGlslAttributeConditions      (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const;
+       static tcu::Vec4                                                getFormatThreshold                      (VkFormat format);
+
+       const std::vector<AttributeInfo>                m_attributeInfos;
+       const BindingMapping                                    m_bindingMapping;
+};
+
+class GlslTypeCombinationsIterator : public CombinationsIterator< std::vector<VertexInputTest::GlslType> >
+{
+public:
+                                                                                                       GlslTypeCombinationsIterator    (deUint32 numValues, deUint32 combinationSize);
+       virtual                                                                                 ~GlslTypeCombinationsIterator   (void) {}
+
+protected:
+       virtual std::vector<VertexInputTest::GlslType>  getCombinationValue                             (const std::vector<deUint32>& combination);
+
+private:
+       std::vector<VertexInputTest::GlslType>                  m_combinationValue;
+};
+
+class VertexInputInstance : public vkt::TestInstance
+{
+public:
+       struct VertexInputAttributeDescription
+       {
+               VertexInputTest::GlslType                       glslType;
+               int                                                                     vertexInputIndex;
+               VkVertexInputAttributeDescription       vkDescription;
+       };
+
+       typedef std::vector<VertexInputAttributeDescription>    AttributeDescriptionList;
+
+                                                                                       VertexInputInstance                     (Context&                                                                                               context,
+                                                                                                                                                const AttributeDescriptionList&                                                attributeDescriptions,
+                                                                                                                                                const std::vector<VkVertexInputBindingDescription>&    bindingDescriptions,
+                                                                                                                                                const std::vector<VkDeviceSize>&                                               bindingOffsets);
+
+       virtual                                                                 ~VertexInputInstance            (void);
+       virtual tcu::TestStatus                                 iterate                                         (void);
+
+
+       static void                                                             writeVertexInputData            (deUint8* destPtr, const VkVertexInputBindingDescription& bindingDescription, const VkDeviceSize bindingOffset, const AttributeDescriptionList& attributes);
+       static void                                                             writeVertexInputValue           (deUint8* destPtr, const VertexInputAttributeDescription& attributes, int indexId);
+
+private:
+       tcu::TestStatus                                                 verifyImage                                     (void);
+
+private:
+       std::vector<VkBuffer>                                   m_vertexBuffers;
+       std::vector<Allocation*>                                m_vertexBufferAllocs;
+
+       const tcu::IVec2                                                m_renderSize;
+       const VkFormat                                                  m_colorFormat;
+
+       Move<VkImage>                                                   m_colorImage;
+       de::MovePtr<Allocation>                                 m_colorImageAlloc;
+       Move<VkImage>                                                   m_depthImage;
+       Move<VkImageView>                                               m_colorAttachmentView;
+       Move<VkRenderPass>                                              m_renderPass;
+       Move<VkFramebuffer>                                             m_framebuffer;
+
+       Move<VkShaderModule>                                    m_vertexShaderModule;
+       Move<VkShaderModule>                                    m_fragmentShaderModule;
+
+       Move<VkPipelineLayout>                                  m_pipelineLayout;
+       Move<VkPipeline>                                                m_graphicsPipeline;
+
+       Move<VkCommandPool>                                             m_cmdPool;
+       Move<VkCommandBuffer>                                   m_cmdBuffer;
+
+       Move<VkFence>                                                   m_fence;
+};
+
+const VertexInputTest::GlslTypeDescription VertexInputTest::s_glslTypeDescriptions[GLSL_TYPE_COUNT] =
+{
+       { "int",        1, 1, GLSL_BASIC_TYPE_INT },
+       { "ivec2",      2, 1, GLSL_BASIC_TYPE_INT },
+       { "ivec3",      3, 1, GLSL_BASIC_TYPE_INT },
+       { "ivec4",      4, 1, GLSL_BASIC_TYPE_INT },
+
+       { "uint",       1, 1, GLSL_BASIC_TYPE_UINT },
+       { "uvec2",      2, 1, GLSL_BASIC_TYPE_UINT },
+       { "uvec3",      3, 1, GLSL_BASIC_TYPE_UINT },
+       { "uvec4",      4, 1, GLSL_BASIC_TYPE_UINT },
+
+       { "float",      1, 1, GLSL_BASIC_TYPE_FLOAT },
+       { "vec2",       2, 1, GLSL_BASIC_TYPE_FLOAT },
+       { "vec3",       3, 1, GLSL_BASIC_TYPE_FLOAT },
+       { "vec4",       4, 1, GLSL_BASIC_TYPE_FLOAT },
+       { "mat2",       2, 2, GLSL_BASIC_TYPE_FLOAT },
+       { "mat3",       3, 3, GLSL_BASIC_TYPE_FLOAT },
+       { "mat4",       4, 4, GLSL_BASIC_TYPE_FLOAT },
+
+       { "double",     1, 1, GLSL_BASIC_TYPE_DOUBLE },
+       { "dvec2",      2, 1, GLSL_BASIC_TYPE_DOUBLE },
+       { "dvec3",      3, 1, GLSL_BASIC_TYPE_DOUBLE },
+       { "dvec4",      4, 1, GLSL_BASIC_TYPE_DOUBLE },
+       { "dmat2",      2, 2, GLSL_BASIC_TYPE_DOUBLE },
+       { "dmat3",      3, 3, GLSL_BASIC_TYPE_DOUBLE },
+       { "dmat4",      4, 4, GLSL_BASIC_TYPE_DOUBLE }
+};
+
+
+VertexInputTest::VertexInputTest (tcu::TestContext&                                            testContext,
+                                                                 const std::string&                                    name,
+                                                                 const std::string&                                    description,
+                                                                 const std::vector<AttributeInfo>&             attributeInfos,
+                                                                 BindingMapping                                                bindingMapping)
+
+       : vkt::TestCase                 (testContext, name, description)
+       , m_attributeInfos              (attributeInfos)
+       , m_bindingMapping              (bindingMapping)
+{
+}
+
+TestInstance* VertexInputTest::createInstance (Context& context) const
+{
+       // Create enough binding descriptions with random offsets
+       std::vector<VkVertexInputBindingDescription>    bindingDescriptions;
+       std::vector<VkDeviceSize>                                               bindingOffsets;
+
+       for (size_t bindingNdx = 0; bindingNdx < m_attributeInfos.size() * 2; bindingNdx++)
+       {
+               // Use STEP_RATE_VERTEX in even bindings and STEP_RATE_INSTANCE in odd bindings
+               const VkVertexInputRate                                         inputRate                       = (bindingNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+
+               // .strideInBytes will be updated when creating the attribute descriptions
+               const VkVertexInputBindingDescription   bindingDescription      =
+               {
+                       (deUint32)bindingNdx,   // deUint32                             binding;
+                       0,                                              // deUint32                             stride;
+                       inputRate                               // VkVertexInputRate    inputRate;
+               };
+
+               bindingDescriptions.push_back(bindingDescription);
+               bindingOffsets.push_back(4 * bindingNdx);
+       }
+
+       // Create attribute descriptions, assign them to bindings and update .strideInBytes
+       std::vector<VertexInputInstance::VertexInputAttributeDescription>       attributeDescriptions;
+       deUint32                                                                                                                        attributeLocation               = 0;
+       std::vector<deUint32>                                                                                           attributeOffsets                        (bindingDescriptions.size(), 0);
+
+       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+       {
+               const AttributeInfo&            attributeInfo                   = m_attributeInfos[attributeNdx];
+               const GlslTypeDescription&      glslTypeDescription             = s_glslTypeDescriptions[attributeInfo.glslType];
+               const deUint32                          inputSize                               = getVertexFormatSize(attributeInfo.vkType);
+               deUint32                                        attributeBinding;
+
+               if (m_bindingMapping == BINDING_MAPPING_ONE_TO_ONE)
+               {
+                       if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+                       {
+                               attributeBinding = (deUint32)attributeNdx * 2; // Odd binding number
+                       }
+                       else // attributeInfo.inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
+                       {
+                               attributeBinding = (deUint32)attributeNdx * 2 + 1; // Even binding number
+                       }
+               }
+               else // m_bindingMapping == BINDING_MAPPING_ONE_TO_MANY
+               {
+                       if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+                       {
+                               attributeBinding = 0;
+                       }
+                       else // attributeInfo.inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
+                       {
+                               attributeBinding = 1;
+                       }
+               }
+
+               for (int descNdx = 0; descNdx < glslTypeDescription.vertexInputCount; descNdx++)
+               {
+                       const VertexInputInstance::VertexInputAttributeDescription attributeDescription =
+                       {
+                               attributeInfo.glslType,                                                 // GlslType     glslType;
+                               descNdx,                                                                                // int          index;
+                               {
+                                       attributeLocation,                                                      // deUint32     location;
+                                       attributeBinding,                                                       // deUint32     binding;
+                                       attributeInfo.vkType,                                           // VkFormat     format;
+                                       attributeOffsets[attributeBinding],                     // deUint32     offset;
+                               },
+                       };
+
+                       bindingDescriptions[attributeBinding].stride += inputSize;
+                       attributeOffsets[attributeBinding] += inputSize;
+
+                       attributeLocation++;
+
+                       attributeDescriptions.push_back(attributeDescription);
+               }
+       }
+
+       return new VertexInputInstance(context, attributeDescriptions, bindingDescriptions, bindingOffsets);
+}
+
+void VertexInputTest::initPrograms (SourceCollections& programCollection) const
+{
+       std::ostringstream vertexSrc;
+
+       vertexSrc << "#version 440\n"
+                         << getGlslInputDeclarations()
+                         << "layout(location = 0) out highp vec4 vtxColor;\n"
+                         << "out gl_PerVertex {\n"
+                         << "  vec4 gl_Position;\n"
+                         << "};\n"
+                         << "double abs (double x) { if (x < 0.0LF) return -x; else return x; }\n" // NOTE: Currently undefined in glslang ??
+                         << "void main (void)\n"
+                         << "{\n"
+                         << getGlslVertexCheck()
+                         << "}\n";
+
+       programCollection.glslSources.add("attribute_test_vert") << glu::VertexSource(vertexSrc.str());
+
+       programCollection.glslSources.add("attribute_test_frag") << glu::FragmentSource(
+               "#version 440\n"
+               "layout(location = 0) in highp vec4 vtxColor;\n"
+               "layout(location = 0) out highp vec4 fragColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "       fragColor = vtxColor;\n"
+               "}\n");
+}
+
+std::string VertexInputTest::getGlslInputDeclarations (void) const
+{
+       std::ostringstream      glslInputs;
+       deUint32                        location = 0;
+
+       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+       {
+               const GlslTypeDescription& glslTypeDesc = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType];
+
+               glslInputs << "layout(location = " << location << ") in highp " << glslTypeDesc.name << " attr" << attributeNdx << ";\n";
+               location += glslTypeDesc.vertexInputCount;
+       }
+
+       return glslInputs.str();
+}
+
+std::string VertexInputTest::getGlslVertexCheck (void) const
+{
+       std::ostringstream      glslCode;
+       int                                     totalInputComponentCount        = 0;
+
+
+       glslCode << "   int okCount = 0;\n";
+
+       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+       {
+               glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], (deUint32)attributeNdx);
+
+               const int vertexInputCount      = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
+               totalInputComponentCount        += vertexInputCount * VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputComponentCount;
+       }
+
+       glslCode <<
+               "       if (okCount == " << totalInputComponentCount << ")\n"
+               "       {\n"
+               "               if (gl_InstanceID == 0)\n"
+               "                       vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
+               "               else\n"
+               "                       vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+               "       }\n"
+               "       else\n"
+               "       {\n"
+               "               vtxColor = vec4(okCount / float(" << totalInputComponentCount << "), 0.0f, 0.0f, 1.0);\n" <<
+               "       }\n\n"
+               "       if (gl_InstanceID == 0)\n"
+               "       {\n"
+               "               if (gl_VertexID == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+               "               else gl_Position = vec4(0.0);\n"
+               "       }\n"
+               "       else\n"
+               "       {\n"
+               "               if (gl_VertexID == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+               "               else if (gl_VertexID == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
+               "               else gl_Position = vec4(0.0);\n"
+               "       }\n";
+
+       return glslCode.str();
+}
+
+std::string VertexInputTest::getGlslAttributeConditions (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const
+{
+       std::ostringstream      glslCode;
+       std::ostringstream      attributeVar;
+       const std::string       indexId                         = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexID" : "gl_InstanceID";
+       const int                       componentCount          = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
+       const int                       vertexInputCount        = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
+       const deUint32          totalComponentCount     = componentCount * vertexInputCount;
+       const tcu::Vec4         threshold                       = getFormatThreshold(attributeInfo.vkType);
+       deUint32                        componentIndex          = 0;
+
+       attributeVar << "attr" << attributeIndex;
+
+       glslCode << std::fixed;
+
+       for (int columnNdx = 0; columnNdx< vertexInputCount; columnNdx++)
+       {
+               for (int rowNdx = 0; rowNdx < componentCount; rowNdx++)
+               {
+                       std::string accessStr;
+                       {
+                               // Build string representing the access to the attribute component
+                               std::ostringstream accessStream;
+                               accessStream << attributeVar.str();
+
+                               if (vertexInputCount == 1)
+                               {
+                                       if (componentCount > 1)
+                                               accessStream << "[" << rowNdx << "]";
+                               }
+                               else
+                               {
+                                       accessStream << "[" << columnNdx << "][" << rowNdx << "]";
+                               }
+
+                               accessStr = accessStream.str();
+                       }
+
+                       if (isVertexFormatSint(attributeInfo.vkType))
+                       {
+                               glslCode << "\tif (" << accessStr << " == -(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+                       }
+                       else if (isVertexFormatUint(attributeInfo.vkType))
+                       {
+                               glslCode << "\tif (" << accessStr << " == uint(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+                       }
+                       else if (isVertexFormatSfloat(attributeInfo.vkType))
+                       {
+                               if (VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
+                               {
+                                       glslCode << "\tif (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double(" << threshold[rowNdx] << "))\n";
+                               }
+                               else
+                               {
+                                       glslCode << "\tif (abs(" << accessStr << " + (0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                               }
+                       }
+                       else if (isVertexFormatSscaled(attributeInfo.vkType))
+                       {
+                               glslCode << "\tif (abs(" << accessStr << " + (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+                       }
+                       else if (isVertexFormatUscaled(attributeInfo.vkType))
+                       {
+                               glslCode << "\t if (abs(" << accessStr << " - (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+                       }
+                       else if (isVertexFormatSnorm(attributeInfo.vkType))
+                       {
+                               const float representableDiff = getRepresentableDifferenceSnorm(attributeInfo.vkType);
+
+                               glslCode << "\tif (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                       }
+                       else if (isVertexFormatUnorm(attributeInfo.vkType) || isVertexFormatSRGB(attributeInfo.vkType))
+                       {
+                               const float representableDiff = getRepresentableDifferenceUnorm(attributeInfo.vkType);
+
+                               glslCode << "\tif (abs(" << accessStr << " - " << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                       }
+                       else
+                       {
+                               DE_ASSERT(false);
+                       }
+
+                       glslCode << "\t\tokCount++;\n\n";
+
+                       componentIndex++;
+               }
+       }
+       return glslCode.str();
+}
+
+tcu::Vec4 VertexInputTest::getFormatThreshold (VkFormat format)
+{
+       using tcu::Vec4;
+
+       switch (format)
+       {
+               case VK_FORMAT_R32_SFLOAT:
+               case VK_FORMAT_R32G32_SFLOAT:
+               case VK_FORMAT_R32G32B32_SFLOAT:
+               case VK_FORMAT_R32G32B32A32_SFLOAT:
+               case VK_FORMAT_R64_SFLOAT:
+               case VK_FORMAT_R64G64_SFLOAT:
+               case VK_FORMAT_R64G64B64_SFLOAT:
+               case VK_FORMAT_R64G64B64A64_SFLOAT:
+                       return Vec4(0.00001f);
+
+               default:
+                       break;
+       }
+
+       if (isVertexFormatSnorm(format))
+       {
+               return Vec4(1.5f * getRepresentableDifferenceSnorm(format));
+       }
+       else if (isVertexFormatUnorm(format))
+       {
+               return Vec4(1.5f * getRepresentableDifferenceUnorm(format));
+       }
+
+       return Vec4(0.001f);
+}
+
+GlslTypeCombinationsIterator::GlslTypeCombinationsIterator (deUint32 numValues, deUint32 combinationSize)
+       : CombinationsIterator< std::vector<VertexInputTest::GlslType> >        (numValues, combinationSize)
+       , m_combinationValue                                                                                            (std::vector<VertexInputTest::GlslType>(combinationSize))
+{
+       DE_ASSERT(numValues <= VertexInputTest::GLSL_TYPE_COUNT);
+}
+
+std::vector<VertexInputTest::GlslType> GlslTypeCombinationsIterator::getCombinationValue (const std::vector<deUint32>& combination)
+{
+       for (size_t combinationItemNdx = 0; combinationItemNdx < combination.size(); combinationItemNdx++)
+               m_combinationValue[combinationItemNdx] = (VertexInputTest::GlslType)combination[combinationItemNdx];
+
+       return m_combinationValue;
+}
+
+VertexInputInstance::VertexInputInstance (Context&                                                                                             context,
+                                                                                 const AttributeDescriptionList&                                               attributeDescriptions,
+                                                                                 const std::vector<VkVertexInputBindingDescription>&   bindingDescriptions,
+                                                                                 const std::vector<VkDeviceSize>&                                              bindingOffsets)
+       : vkt::TestInstance                     (context)
+       , m_renderSize                          (16, 16)
+       , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
+{
+       DE_ASSERT(bindingDescriptions.size() == bindingOffsets.size());
+
+       const DeviceInterface&          vk                                              = context.getDeviceInterface();
+       const VkDevice                          vkDevice                                = context.getDevice();
+       const deUint32                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
+       SimpleAllocator                         memAlloc                                (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+       const VkComponentMapping        componentMappingRGBA    = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
+
+       // Create color image
+       {
+               const VkImageCreateInfo colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+                       m_colorFormat,                                                                                                                          // VkFormat                                     format;
+                       { m_renderSize.x(), m_renderSize.y(), 1u },                                                                     // VkExtent3D                           extent;
+                       1u,                                                                                                                                                     // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                     arrayLayers;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        initialLayout;
+               };
+
+               m_colorImage                    = createImage(vk, vkDevice, &colorImageParams);
+
+               // Allocate and bind color image memory
+               m_colorImageAlloc               = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+       }
+
+       // Create color attachment view
+       {
+               const VkImageViewCreateInfo colorAttachmentViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,               // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       0u,                                                                                             // VkImageViewCreateFlags       flags;
+                       *m_colorImage,                                                                  // VkImage                                      image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                  // VkImageViewType                      viewType;
+                       m_colorFormat,                                                                  // VkFormat                                     format;
+                       componentMappingRGBA,                                                   // VkComponentMapping           components;
+                       { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },  // VkImageSubresourceRange      subresourceRange;
+               };
+
+               m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+       }
+
+       // Create render pass
+       {
+               const VkAttachmentDescription colorAttachmentDescription =
+               {
+                       0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
+                       m_colorFormat,                                                                          // 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 colorAttachmentReference =
+               {
+                       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;
+                       &colorAttachmentReference,                                                      // 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;
+                       &colorAttachmentDescription,                                            // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                      sType;
+                       DE_NULL,                                                                                        // const void*                          pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags     flags;
+                       *m_renderPass,                                                                          // VkRenderPass                         renderPass;
+                       1u,                                                                                                     // deUint32                                     attachmentCount;
+                       &m_colorAttachmentView.get(),                                           // const VkImageView*           pAttachments;
+                       (deUint32)m_renderSize.x(),                                                     // deUint32                                     width;
+                       (deUint32)m_renderSize.y(),                                                     // deUint32                                     height;
+                       1u                                                                                                      // deUint32                                     layers;
+               };
+
+               m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // const void*                                          pNext;
+                       0u,                                                                                                     // VkPipelineLayoutCreateFlags          flags;
+                       0u,                                                                                                     // deUint32                                                     setLayoutCount;
+                       DE_NULL,                                                                                        // const VkDescriptorSetLayout*         pSetLayouts;
+                       0u,                                                                                                     // deUint32                                                     pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*           pPushConstantRanges;
+               };
+
+               m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       m_vertexShaderModule    = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_vert"), 0);
+       m_fragmentShaderModule  = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_frag"), 0);
+
+
+       // Create pipeline
+       {
+               const VkPipelineShaderStageCreateInfo shaderStageParams[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;
+                               *m_vertexShaderModule,                                                                          // 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;
+                               *m_fragmentShaderModule,                                                                        // VkShaderModule                                               module;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       }
+               };
+
+               // Create vertex attribute array and check if their VK formats are supported
+               std::vector<VkVertexInputAttributeDescription> vkAttributeDescriptions;
+               for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
+               {
+                       const VkVertexInputAttributeDescription& attributeDescription = attributeDescriptions[attributeNdx].vkDescription;
+
+                       if (!isSupportedVertexFormat(context.getInstanceInterface(), context.getPhysicalDevice(), attributeDescription.format))
+                               throw tcu::NotSupportedError(std::string("Unsupported format for vertex input: ") + getFormatName(attributeDescription.format));
+
+                       vkAttributeDescriptions.push_back(attributeDescription);
+               }
+
+               const VkPipelineVertexInputStateCreateInfo      vertexInputStateParams  =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // VkPipelineVertexInputStateCreateFlags        flags;
+                       (deUint32)bindingDescriptions.size(),                                                   // deUint32                                                                     vertexBindingDescriptionCount;
+                       bindingDescriptions.data(),                                                                             // const VkVertexInputBindingDescription*       pVertexBindingDescriptions;
+                       (deUint32)vkAttributeDescriptions.size(),                                               // deUint32                                                                     vertexAttributeDescriptionCount;
+                       vkAttributeDescriptions.data()                                                                  // 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_STRIP,                                                   // VkPrimitiveTopology                                          topology;
+                       false                                                                                                                   // VkBool32                                                                     primitiveRestartEnable;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        x;
+                       0.0f,                                           // float        y;
+                       (float)m_renderSize.x(),        // float        width;
+                       (float)m_renderSize.y(),        // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+               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                                                             scissorCount;
+                       &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;
+                       VK_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,                                                                                                            // VkBlendFactor                        srcColorBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlendFactor                        dstColorBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp                            colorBlendOp;
+                       VK_BLEND_FACTOR_ONE,                                                                                                            // VkBlendFactor                        srcAlphaBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlendFactor                        dstAlphaBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp                            alphaBlendOp;
+                       VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                                           // VkColorComponentFlags        colorWriteMask;
+                               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 VkPipelineMultisampleStateCreateInfo      multisampleStateParams  =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                          // VkSampleCountFlagBits                                        rasterizationSamples;
+                       false,                                                                                                          // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                           // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
+                       false,                                                                                                          // VkBool32                                                                     alphaToCoverageEnable;
+                       false                                                                                                           // VkBool32                                                                     alphaToOneEnable;
+               };
+
+               const VkPipelineDynamicStateCreateInfo  dynamicStateParams              =
+               {
+                       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;
+               };
+
+               VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                          pNext;
+                       0u,                                                                                                                     // VkPipelineDepthStencilStateCreateFlags       flags;
+                       false,                                                                                                          // VkBool32                                                                     depthTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     depthWriteEnable;
+                       VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                                                          depthCompareOp;
+                       false,                                                                                                          // VkBool32                                                                     depthBoundsTestEnable;
+                       false,                                                                                                          // VkBool32                                                                     stencilTestEnable;
+                       // VkStencilOpState     front;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       // VkStencilOpState     back;
+                       {
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  failOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  passOp;
+                               VK_STENCIL_OP_KEEP,             // VkStencilOp  depthFailOp;
+                               VK_COMPARE_OP_NEVER,    // VkCompareOp  compareOp;
+                               0u,                                             // deUint32             compareMask;
+                               0u,                                             // deUint32             writeMask;
+                               0u,                                             // deUint32             reference;
+                       },
+                       -1.0f,                                                                                                          // float                        minDepthBounds;
+                       +1.0f,                                                                                                          // float                        maxDepthBounds;
+               };
+
+               const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       0u,                                                                                                     // VkPipelineCreateFlags                                                        flags;
+                       2u,                                                                                                     // deUint32                                                                                     stageCount;
+                       shaderStageParams,                                                                      // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &depthStencilStateParams,                                                       // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateParams,                                                            // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *m_pipelineLayout,                                                                      // VkPipelineLayout                                                                     layout;
+                       *m_renderPass,                                                                          // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               m_graphicsPipeline      = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create vertex buffer
+       {
+               const VkBufferCreateInfo vertexBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkBufferCreateFlags  flags;
+                       4096u,                                                                          // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                      // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                     // deUint32                             queueFamilyIndexCount;
+                       &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+               };
+
+               // Upload data for each vertex input binding
+               for (deUint32 bindingNdx = 0; bindingNdx < bindingDescriptions.size(); bindingNdx++)
+               {
+                       Move<VkBuffer>                  vertexBuffer            = createBuffer(vk, vkDevice, &vertexBufferParams);
+                       de::MovePtr<Allocation> vertexBufferAlloc       = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
+
+                       VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset()));
+
+                       writeVertexInputData((deUint8*)vertexBufferAlloc->getHostPtr(), bindingDescriptions[bindingNdx], bindingOffsets[bindingNdx], attributeDescriptions);
+                       flushMappedMemoryRange(vk, vkDevice, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+
+                       m_vertexBuffers.push_back(vertexBuffer.disown());
+                       m_vertexBufferAllocs.push_back(vertexBufferAlloc.release());
+               }
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,     // VkStructureType                              sType;
+                       DE_NULL,                                                                        // const void*                                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,           // VkCommandPoolCreateFlags             flags;
+                       queueFamilyIndex,                                                       // deUint32                                             queueFamilyIndex;
+               };
+
+               m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *m_cmdPool,                                                                             // VkCommandPool                        commandPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCommandBufferLevel         level;
+                       1u                                                                                              // deUint32                                     bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCommandBufferUsageFlags            flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       false,                                                                                  // VkBool32                                                     occlusionQueryEnable;
+                       0u,                                                                                             // VkQueryControlFlags                          queryFlags;
+                       0u                                                                                              // VkQueryPipelineStatisticFlags        pipelineStatistics;
+               };
+
+               const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *m_renderPass,                                                                                  // VkRenderPass                 renderPass;
+                       *m_framebuffer,                                                                                 // VkFramebuffer                framebuffer;
+                       { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },   // VkRect2D                             renderArea;
+                       1u,                                                                                                             // deUint32                             clearValueCount;
+                       &attachmentClearValue                                                                   // const VkClearValue*  pClearValues;
+               };
+
+               m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
+
+               VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
+
+               std::vector<VkBuffer> vertexBuffers;
+               for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
+                       vertexBuffers.push_back(m_vertexBuffers[bufferNdx]);
+
+               if (vertexBuffers.size() <= 1)
+               {
+                       // One vertex buffer
+                       vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, (deUint32)vertexBuffers.size(), vertexBuffers.data(), bindingOffsets.data());
+               }
+               else
+               {
+                       // Smoke-test vkCmdBindVertexBuffers(..., startBinding, ... )
+
+                       const deUint32 firstHalfLength = (deUint32)vertexBuffers.size() / 2;
+                       const deUint32 secondHalfLength = firstHalfLength + (deUint32)(vertexBuffers.size() % 2);
+
+                       // Bind first half of vertex buffers
+                       vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, firstHalfLength, vertexBuffers.data(), bindingOffsets.data());
+
+                       // Bind second half of vertex buffers
+                       vk.cmdBindVertexBuffers(*m_cmdBuffer, firstHalfLength, secondHalfLength,
+                                                                       vertexBuffers.data() + firstHalfLength,
+                                                                       bindingOffsets.data() + firstHalfLength);
+               }
+
+               vk.cmdDraw(*m_cmdBuffer, 4, 2, 0, 0);
+
+               vk.cmdEndRenderPass(*m_cmdBuffer);
+               VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               m_fence = createFence(vk, vkDevice, &fenceParams);
+       }
+}
+
+VertexInputInstance::~VertexInputInstance (void)
+{
+       const DeviceInterface&          vk                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice        = m_context.getDevice();
+
+       for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
+               vk.destroyBuffer(vkDevice, m_vertexBuffers[bufferNdx], DE_NULL);
+
+       for (size_t allocNdx = 0; allocNdx < m_vertexBufferAllocs.size(); allocNdx++)
+               delete m_vertexBufferAllocs[allocNdx];
+}
+
+void VertexInputInstance::writeVertexInputData(deUint8* destPtr, const VkVertexInputBindingDescription& bindingDescription, const VkDeviceSize bindingOffset, const AttributeDescriptionList& attributes)
+{
+       const deUint32 vertexCount = (bindingDescription.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
+
+       deUint8* destOffsetPtr = ((deUint8 *)destPtr) + bindingOffset;
+       for (deUint32 vertexNdx = 0; vertexNdx < vertexCount; vertexNdx++)
+       {
+               deUint32 vertexInputOffset = 0;
+               for (size_t attributeNdx = 0; attributeNdx < attributes.size(); attributeNdx++)
+               {
+                       const VertexInputAttributeDescription& attribDesc = attributes[attributeNdx];
+
+                       // Only write vertex input data to bindings referenced by attribute descriptions
+                       if (attribDesc.vkDescription.binding == bindingDescription.binding)
+                       {
+                               writeVertexInputValue(destOffsetPtr + vertexInputOffset, attribDesc, vertexNdx);
+                               vertexInputOffset += getVertexFormatSize(attribDesc.vkDescription.format);
+                       }
+               }
+               DE_ASSERT(vertexInputOffset <= bindingDescription.stride);
+               destOffsetPtr += bindingDescription.stride;
+       }
+}
+
+void writeVertexInputValueSint (deUint8* destPtr, VkFormat format, int componentNdx, deInt32 value)
+{
+       const deUint32  componentSize   = getVertexFormatComponentSize(format);
+       deUint8*                destFormatPtr   = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+       switch (componentSize)
+       {
+               case 1:
+                       *((deInt8*)destFormatPtr) = (deInt8)value;
+                       break;
+
+               case 2:
+                       *((deInt16*)destFormatPtr) = (deInt16)value;
+                       break;
+
+               case 4:
+                       *((deInt32*)destFormatPtr) = (deInt32)value;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+}
+
+void writeVertexInputValueUint (deUint8* destPtr, VkFormat format, int componentNdx, deUint32 value)
+{
+       const deUint32  componentSize   = getVertexFormatComponentSize(format);
+       deUint8*                destFormatPtr   = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+       switch (componentSize)
+       {
+               case 1:
+                       *((deUint8 *)destFormatPtr) = (deUint8)value;
+                       break;
+
+               case 2:
+                       *((deUint16 *)destFormatPtr) = (deUint16)value;
+                       break;
+
+               case 4:
+                       *((deUint32 *)destFormatPtr) = (deUint32)value;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+}
+
+void writeVertexInputValueSfloat (deUint8* destPtr, VkFormat format, int componentNdx, float value)
+{
+       const deUint32  componentSize   = getVertexFormatComponentSize(format);
+       deUint8*                destFormatPtr   = ((deUint8*)destPtr) + componentSize * componentNdx;
+
+       switch (componentSize)
+       {
+               case 2:
+                       *((deFloat16*)destFormatPtr) = deFloat32To16(value);
+                       break;
+
+               case 4:
+                       *((float*)destFormatPtr) = value;
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+}
+
+void VertexInputInstance::writeVertexInputValue (deUint8* destPtr, const VertexInputAttributeDescription& attribute, int indexId)
+{
+       const int               vertexInputCount        = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputCount;
+       const int               componentCount          = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputComponentCount;
+       const deUint32  totalComponentCount     = componentCount * vertexInputCount;
+       const deUint32  vertexInputIndex        = indexId * totalComponentCount + attribute.vertexInputIndex * componentCount;
+       const bool              hasBGROrder                     = isVertexFormatComponentOrderBGR(attribute.vkDescription.format);
+       int                             swizzledNdx;
+
+       for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
+       {
+               if (hasBGROrder)
+               {
+                       if (componentNdx == 0)
+                               swizzledNdx = 2;
+                       else if (componentNdx == 2)
+                               swizzledNdx = 0;
+                       else
+                               swizzledNdx = componentNdx;
+               }
+               else
+                       swizzledNdx = componentNdx;
+
+               switch (attribute.glslType)
+               {
+                       case VertexInputTest::GLSL_TYPE_INT:
+                       case VertexInputTest::GLSL_TYPE_IVEC2:
+                       case VertexInputTest::GLSL_TYPE_IVEC3:
+                       case VertexInputTest::GLSL_TYPE_IVEC4:
+                               writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, -(vertexInputIndex + swizzledNdx));
+                               break;
+
+                       case VertexInputTest::GLSL_TYPE_UINT:
+                       case VertexInputTest::GLSL_TYPE_UVEC2:
+                       case VertexInputTest::GLSL_TYPE_UVEC3:
+                       case VertexInputTest::GLSL_TYPE_UVEC4:
+                               writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx, vertexInputIndex + swizzledNdx);
+                               break;
+
+                       case VertexInputTest::GLSL_TYPE_FLOAT:
+                       case VertexInputTest::GLSL_TYPE_VEC2:
+                       case VertexInputTest::GLSL_TYPE_VEC3:
+                       case VertexInputTest::GLSL_TYPE_VEC4:
+                       case VertexInputTest::GLSL_TYPE_MAT2:
+                       case VertexInputTest::GLSL_TYPE_MAT3:
+                       case VertexInputTest::GLSL_TYPE_MAT4:
+                               if (isVertexFormatSfloat(attribute.vkDescription.format))
+                               {
+                                       writeVertexInputValueSfloat(destPtr, attribute.vkDescription.format, componentNdx, -(0.01f * (float)(vertexInputIndex + swizzledNdx)));
+                               }
+                               else if (isVertexFormatSscaled(attribute.vkDescription.format))
+                               {
+                                       writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, -(vertexInputIndex + swizzledNdx));
+                               }
+                               else if (isVertexFormatUscaled(attribute.vkDescription.format) || isVertexFormatUnorm(attribute.vkDescription.format) || isVertexFormatSRGB(attribute.vkDescription.format))
+                               {
+                                       writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx, vertexInputIndex + swizzledNdx);
+                               }
+                               else if (isVertexFormatSnorm(attribute.vkDescription.format))
+                               {
+                                       const deInt32 minIntValue = -((1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8 - 1))) + 1;
+                                       writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx, minIntValue + (vertexInputIndex + swizzledNdx));
+                               }
+                               else
+                                       DE_ASSERT(false);
+                               break;
+
+                       case VertexInputTest::GLSL_TYPE_DOUBLE:
+                       case VertexInputTest::GLSL_TYPE_DVEC2:
+                       case VertexInputTest::GLSL_TYPE_DVEC3:
+                       case VertexInputTest::GLSL_TYPE_DVEC4:
+                       case VertexInputTest::GLSL_TYPE_DMAT2:
+                       case VertexInputTest::GLSL_TYPE_DMAT3:
+                       case VertexInputTest::GLSL_TYPE_DMAT4:
+                               *(reinterpret_cast<double *>(destPtr) + componentNdx) = -0.01 * (vertexInputIndex + swizzledNdx);
+
+                               break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+}
+
+tcu::TestStatus VertexInputInstance::iterate (void)
+{
+       const DeviceInterface&          vk                      = m_context.getDeviceInterface();
+       const VkDevice                          vkDevice        = m_context.getDevice();
+       const VkQueue                           queue           = m_context.getUniversalQueue();
+       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;
+               &m_cmdBuffer.get(),                             // const VkCommandBuffer*       pCommandBuffers;
+               0u,                                                             // deUint32                                     signalSemaphoreCount;
+               DE_NULL                                                 // const VkSemaphore*           pSignalSemaphores;
+       };
+
+       VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
+       VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+       return verifyImage();
+}
+
+bool VertexInputTest::isCompatibleType (VkFormat format, GlslType glslType)
+{
+       const GlslTypeDescription glslTypeDesc = s_glslTypeDescriptions[glslType];
+
+       if ((deUint32)s_glslTypeDescriptions[glslType].vertexInputComponentCount == getVertexFormatComponentCount(format))
+       {
+               switch (glslTypeDesc.basicType)
+               {
+                       case GLSL_BASIC_TYPE_INT:
+                               return isVertexFormatSint(format);
+
+                       case GLSL_BASIC_TYPE_UINT:
+                               return isVertexFormatUint(format);
+
+                       case GLSL_BASIC_TYPE_FLOAT:
+                               return getVertexFormatComponentSize(format) <= 4 && (isVertexFormatSfloat(format) || isVertexFormatSnorm(format) || isVertexFormatUnorm(format) || isVertexFormatSscaled(format) || isVertexFormatUscaled(format) || isVertexFormatSRGB(format));
+
+                       case GLSL_BASIC_TYPE_DOUBLE:
+                               return isVertexFormatSfloat(format) && getVertexFormatComponentSize(format) == 8;
+
+                       default:
+                               DE_ASSERT(false);
+                               return false;
+               }
+       }
+       else
+               return false;
+}
+
+tcu::TestStatus VertexInputInstance::verifyImage (void)
+{
+       bool                                                    compareOk                       = false;
+       const tcu::TextureFormat                tcuColorFormat          = mapVkFormat(m_colorFormat);
+       tcu::TextureLevel                               reference                       (tcuColorFormat, m_renderSize.x(), m_renderSize.y());
+       const tcu::PixelBufferAccess    refRedSubregion         (tcu::getSubregion(reference.getAccess(),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.x() * 0.0f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.y() * 0.0f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
+       const tcu::PixelBufferAccess    refBlueSubregion        (tcu::getSubregion(reference.getAccess(),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.y() * 0.0f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
+                                                                                                                                                  deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
+
+       // Create reference image
+       tcu::clear(reference.getAccess(), defaultClearColor(tcuColorFormat));
+       tcu::clear(refRedSubregion, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
+       tcu::clear(refBlueSubregion, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
+
+       // Compare result with reference image
+       {
+               const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
+               const VkDevice                                  vkDevice                        = m_context.getDevice();
+               const VkQueue                                   queue                           = m_context.getUniversalQueue();
+               const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+               SimpleAllocator                                 allocator                       (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+               de::MovePtr<tcu::TextureLevel>  result                          = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
+
+               compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+                                                                                                                         "IntImageCompare",
+                                                                                                                         "Image comparison",
+                                                                                                                         reference.getAccess(),
+                                                                                                                         result->getAccess(),
+                                                                                                                         tcu::UVec4(2, 2, 2, 2),
+                                                                                                                         tcu::IVec3(1, 1, 0),
+                                                                                                                         true,
+                                                                                                                         tcu::COMPARE_LOG_RESULT);
+       }
+
+       if (compareOk)
+               return tcu::TestStatus::pass("Result image matches reference");
+       else
+               return tcu::TestStatus::fail("Image mismatch");
+}
+
+std::string getAttributeInfoCaseName (const VertexInputTest::AttributeInfo& attributeInfo)
+{
+       std::ostringstream      caseName;
+       const std::string       formatName      = getFormatName(attributeInfo.vkType);
+
+       caseName << VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].name << "_as_" << de::toLower(formatName.substr(10)) << "_rate_";
+
+       if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+               caseName <<  "vertex";
+       else
+               caseName <<  "instance";
+
+       return caseName.str();
+}
+
+std::string getAttributeInfosCaseName (const std::vector<VertexInputTest::AttributeInfo>& attributeInfos)
+{
+       std::ostringstream caseName;
+
+       for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+       {
+               caseName << getAttributeInfoCaseName(attributeInfos[attributeNdx]);
+
+               if (attributeNdx < attributeInfos.size() - 1)
+                       caseName << "-";
+       }
+
+       return caseName.str();
+}
+
+std::string getAttributeInfoDescription (const VertexInputTest::AttributeInfo& attributeInfo)
+{
+       std::ostringstream caseDesc;
+
+       caseDesc << std::string(VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].name) << " from type " << getFormatName(attributeInfo.vkType) <<  " with ";
+
+       if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
+               caseDesc <<  "vertex input rate ";
+       else
+               caseDesc <<  "instance input rate ";
+
+       return caseDesc.str();
+}
+
+std::string getAttributeInfosDescription (const std::vector<VertexInputTest::AttributeInfo>& attributeInfos)
+{
+       std::ostringstream caseDesc;
+
+       caseDesc << "Uses vertex attributes:\n";
+
+       for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+               caseDesc << "\t- " << getAttributeInfoDescription (attributeInfos[attributeNdx]) << "\n";
+
+       return caseDesc.str();
+}
+
+struct CompatibleFormats
+{
+       VertexInputTest::GlslType       glslType;
+       std::vector<VkFormat>           compatibleVkFormats;
+};
+
+de::MovePtr<tcu::TestCaseGroup> createSingleAttributeTests (tcu::TestContext& testCtx)
+{
+       const VkFormat vertexFormats[] =
+       {
+               // Required, unpacked
+               VK_FORMAT_R8_UNORM,
+               VK_FORMAT_R8_SNORM,
+               VK_FORMAT_R8_UINT,
+               VK_FORMAT_R8_SINT,
+               VK_FORMAT_R8G8_UNORM,
+               VK_FORMAT_R8G8_SNORM,
+               VK_FORMAT_R8G8_UINT,
+               VK_FORMAT_R8G8_SINT,
+               VK_FORMAT_R8G8B8A8_UNORM,
+               VK_FORMAT_R8G8B8A8_SNORM,
+               VK_FORMAT_R8G8B8A8_UINT,
+               VK_FORMAT_R8G8B8A8_SINT,
+               VK_FORMAT_B8G8R8A8_UNORM,
+               VK_FORMAT_R16_UNORM,
+               VK_FORMAT_R16_SNORM,
+               VK_FORMAT_R16_UINT,
+               VK_FORMAT_R16_SINT,
+               VK_FORMAT_R16_SFLOAT,
+               VK_FORMAT_R16G16_UNORM,
+               VK_FORMAT_R16G16_SNORM,
+               VK_FORMAT_R16G16_UINT,
+               VK_FORMAT_R16G16_SINT,
+               VK_FORMAT_R16G16_SFLOAT,
+               VK_FORMAT_R16G16B16A16_UNORM,
+               VK_FORMAT_R16G16B16A16_SNORM,
+               VK_FORMAT_R16G16B16A16_UINT,
+               VK_FORMAT_R16G16B16A16_SINT,
+               VK_FORMAT_R16G16B16A16_SFLOAT,
+               VK_FORMAT_R32_UINT,
+               VK_FORMAT_R32_SINT,
+               VK_FORMAT_R32_SFLOAT,
+               VK_FORMAT_R32G32_UINT,
+               VK_FORMAT_R32G32_SINT,
+               VK_FORMAT_R32G32_SFLOAT,
+               VK_FORMAT_R32G32B32_UINT,
+               VK_FORMAT_R32G32B32_SINT,
+               VK_FORMAT_R32G32B32_SFLOAT,
+               VK_FORMAT_R32G32B32A32_UINT,
+               VK_FORMAT_R32G32B32A32_SINT,
+               VK_FORMAT_R32G32B32A32_SFLOAT,
+
+               // Scaled formats
+               VK_FORMAT_R8G8_USCALED,
+               VK_FORMAT_R8G8_SSCALED,
+               VK_FORMAT_R16_USCALED,
+               VK_FORMAT_R16_SSCALED,
+               VK_FORMAT_R8G8B8_USCALED,
+               VK_FORMAT_R8G8B8_SSCALED,
+               VK_FORMAT_B8G8R8_USCALED,
+               VK_FORMAT_B8G8R8_SSCALED,
+               VK_FORMAT_R8G8B8A8_USCALED,
+               VK_FORMAT_R8G8B8A8_SSCALED,
+               VK_FORMAT_B8G8R8A8_USCALED,
+               VK_FORMAT_B8G8R8A8_SSCALED,
+               VK_FORMAT_R16G16_USCALED,
+               VK_FORMAT_R16G16_SSCALED,
+               VK_FORMAT_R16G16B16_USCALED,
+               VK_FORMAT_R16G16B16_SSCALED,
+               VK_FORMAT_R16G16B16A16_USCALED,
+               VK_FORMAT_R16G16B16A16_SSCALED,
+               
+               // SRGB formats
+               VK_FORMAT_R8_SRGB,
+               VK_FORMAT_R8G8_SRGB,
+               VK_FORMAT_R8G8B8_SRGB,
+               VK_FORMAT_B8G8R8_SRGB,
+               VK_FORMAT_R8G8B8A8_SRGB,
+               VK_FORMAT_B8G8R8A8_SRGB,
+
+               // Double formats
+               VK_FORMAT_R64_SFLOAT,
+               VK_FORMAT_R64G64_SFLOAT,
+               VK_FORMAT_R64G64B64_SFLOAT,
+               VK_FORMAT_R64G64B64A64_SFLOAT,
+       };
+
+       de::MovePtr<tcu::TestCaseGroup> singleAttributeTests (new tcu::TestCaseGroup(testCtx, "single_attribute", "Uses one attribute"));
+
+       for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
+       {
+               for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
+               {
+                       if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
+                       {
+                               // Create test case for RATE_VERTEX
+                               VertexInputTest::AttributeInfo attributeInfo;
+                               attributeInfo.vkType    = vertexFormats[formatNdx];
+                               attributeInfo.glslType  = (VertexInputTest::GlslType)glslTypeNdx;
+                               attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+                               singleAttributeTests->addChild(new VertexInputTest(testCtx,
+                                                                                                                                  getAttributeInfoCaseName(attributeInfo),
+                                                                                                                                  getAttributeInfoDescription(attributeInfo),
+                                                                                                                                  std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
+                                                                                                                                  VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+
+                               // Create test case for RATE_INSTANCE
+                               attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
+
+                               singleAttributeTests->addChild(new VertexInputTest(testCtx,
+                                                                                                                                  getAttributeInfoCaseName(attributeInfo),
+                                                                                                                                  getAttributeInfoDescription(attributeInfo),
+                                                                                                                                  std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
+                                                                                                                                  VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+                       }
+               }
+       }
+
+       return singleAttributeTests;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createMultipleAttributeTests (tcu::TestContext& testCtx)
+{
+       // Required vertex formats, unpacked
+       const VkFormat vertexFormats[] =
+       {
+               VK_FORMAT_R8_UNORM,
+               VK_FORMAT_R8_SNORM,
+               VK_FORMAT_R8_UINT,
+               VK_FORMAT_R8_SINT,
+               VK_FORMAT_R8G8_UNORM,
+               VK_FORMAT_R8G8_SNORM,
+               VK_FORMAT_R8G8_UINT,
+               VK_FORMAT_R8G8_SINT,
+               VK_FORMAT_R8G8B8A8_UNORM,
+               VK_FORMAT_R8G8B8A8_SNORM,
+               VK_FORMAT_R8G8B8A8_UINT,
+               VK_FORMAT_R8G8B8A8_SINT,
+               VK_FORMAT_B8G8R8A8_UNORM,
+               VK_FORMAT_R16_UNORM,
+               VK_FORMAT_R16_SNORM,
+               VK_FORMAT_R16_UINT,
+               VK_FORMAT_R16_SINT,
+               VK_FORMAT_R16_SFLOAT,
+               VK_FORMAT_R16G16_UNORM,
+               VK_FORMAT_R16G16_SNORM,
+               VK_FORMAT_R16G16_UINT,
+               VK_FORMAT_R16G16_SINT,
+               VK_FORMAT_R16G16_SFLOAT,
+               VK_FORMAT_R16G16B16A16_UNORM,
+               VK_FORMAT_R16G16B16A16_SNORM,
+               VK_FORMAT_R16G16B16A16_UINT,
+               VK_FORMAT_R16G16B16A16_SINT,
+               VK_FORMAT_R16G16B16A16_SFLOAT,
+               VK_FORMAT_R32_UINT,
+               VK_FORMAT_R32_SINT,
+               VK_FORMAT_R32_SFLOAT,
+               VK_FORMAT_R32G32_UINT,
+               VK_FORMAT_R32G32_SINT,
+               VK_FORMAT_R32G32_SFLOAT,
+               VK_FORMAT_R32G32B32_UINT,
+               VK_FORMAT_R32G32B32_SINT,
+               VK_FORMAT_R32G32B32_SFLOAT,
+               VK_FORMAT_R32G32B32A32_UINT,
+               VK_FORMAT_R32G32B32A32_SINT,
+               VK_FORMAT_R32G32B32A32_SFLOAT
+       };
+
+       de::MovePtr<tcu::TestCaseGroup> multipleAttributeTests (new tcu::TestCaseGroup(testCtx, "multiple_attributes", "Uses more than one attribute"));
+
+       // Find compatible VK formats for each GLSL vertex type
+       CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
+       {
+               for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
+               {
+                       for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
+                       {
+                               if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
+                                       compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
+                       }
+               }
+       }
+
+       de::Random                                              randomFunc                              (102030);
+       GlslTypeCombinationsIterator    glslTypeCombinationsItr (VertexInputTest::GLSL_TYPE_DOUBLE, 3); // Exclude double values, which are not included in vertexFormats
+       de::MovePtr<tcu::TestCaseGroup> oneToOneAttributeTests  (new tcu::TestCaseGroup(testCtx, "attributes", ""));
+       de::MovePtr<tcu::TestCaseGroup> oneToManyAttributeTests (new tcu::TestCaseGroup(testCtx, "attributes", ""));
+
+       while (glslTypeCombinationsItr.hasNext())
+       {
+               const std::vector<VertexInputTest::GlslType>    glslTypes               = glslTypeCombinationsItr.next();
+               std::vector<VertexInputTest::AttributeInfo>             attributeInfos  (glslTypes.size());
+
+               for (size_t attributeNdx = 0; attributeNdx < attributeInfos.size(); attributeNdx++)
+               {
+                       DE_ASSERT(!compatibleFormats[glslTypes[attributeNdx]].compatibleVkFormats.empty());
+
+                       // Select a random compatible format
+                       const std::vector<VkFormat>& formats = compatibleFormats[glslTypes[attributeNdx]].compatibleVkFormats;
+                       const VkFormat format = formats[randomFunc.getUint32() % formats.size()];
+
+                       attributeInfos[attributeNdx].glslType   = glslTypes[attributeNdx];
+                       attributeInfos[attributeNdx].inputRate  = (attributeNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+                       attributeInfos[attributeNdx].vkType             = format;
+               }
+
+               const std::string       caseName        = getAttributeInfosCaseName(attributeInfos);
+               const std::string       caseDesc        = getAttributeInfosDescription(attributeInfos);
+
+               oneToOneAttributeTests->addChild(new VertexInputTest(testCtx, caseName, caseDesc, attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE));
+               oneToManyAttributeTests->addChild(new VertexInputTest(testCtx, caseName, caseDesc, attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY));
+       }
+
+       de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests    (new tcu::TestCaseGroup(testCtx, "binding_one_to_one", "Each attribute uses a unique binding"));
+       bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
+       multipleAttributeTests->addChild(bindingOneToOneTests.release());
+
+       de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests   (new tcu::TestCaseGroup(testCtx, "binding_one_to_many", "Attributes share the same binding"));
+       bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
+       multipleAttributeTests->addChild(bindingOneToManyTests.release());
+
+       return multipleAttributeTests;
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createVertexInputTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> vertexInputTests (new tcu::TestCaseGroup(testCtx, "vertex_input", ""));
+
+       vertexInputTests->addChild(createSingleAttributeTests(testCtx).release());
+       vertexInputTests->addChild(createMultipleAttributeTests(testCtx).release());
+
+       return vertexInputTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.hpp
new file mode 100644 (file)
index 0000000..161efca
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEVERTEXINPUTTESTS_HPP
+#define _VKTPIPELINEVERTEXINPUTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies 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 Vertex Input Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createVertexInputTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEVERTEXINPUTTESTS_HPP
index bc6c258..4cdf3c7 100644 (file)
  *//*--------------------------------------------------------------------*/
 
 #include "vktPipelineVertexUtil.hpp"
+#include "vkStrUtil.hpp"
 #include "tcuVectorUtil.hpp"
+#include "deStringUtil.hpp"
 
 namespace vkt
 {
 namespace pipeline
 {
 
+using namespace vk;
+
+deUint32 getVertexFormatSize (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_UNORM:
+               case VK_FORMAT_R8_SNORM:
+               case VK_FORMAT_R8_USCALED:
+               case VK_FORMAT_R8_SSCALED:
+               case VK_FORMAT_R8_UINT:
+               case VK_FORMAT_R8_SINT:
+               case VK_FORMAT_R8_SRGB:
+               case VK_FORMAT_R4G4_UNORM_PACK8:
+                       return 1;
+
+               case VK_FORMAT_R8G8_UNORM:
+               case VK_FORMAT_R8G8_SNORM:
+               case VK_FORMAT_R8G8_USCALED:
+               case VK_FORMAT_R8G8_SSCALED:
+               case VK_FORMAT_R8G8_UINT:
+               case VK_FORMAT_R8G8_SINT:
+               case VK_FORMAT_R8G8_SRGB:
+               case VK_FORMAT_R16_UNORM:
+               case VK_FORMAT_R16_SNORM:
+               case VK_FORMAT_R16_USCALED:
+               case VK_FORMAT_R16_SSCALED:
+               case VK_FORMAT_R16_UINT:
+               case VK_FORMAT_R16_SINT:
+               case VK_FORMAT_R16_SFLOAT:
+               case VK_FORMAT_R5G6B5_UNORM_PACK16:
+               case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+                       return 2;
+
+               case VK_FORMAT_R8G8B8_UNORM:
+               case VK_FORMAT_R8G8B8_SNORM:
+               case VK_FORMAT_R8G8B8_USCALED:
+               case VK_FORMAT_R8G8B8_SSCALED:
+               case VK_FORMAT_R8G8B8_UINT:
+               case VK_FORMAT_R8G8B8_SINT:
+               case VK_FORMAT_R8G8B8_SRGB:
+               case VK_FORMAT_B8G8R8_UNORM:
+               case VK_FORMAT_B8G8R8_SNORM:
+               case VK_FORMAT_B8G8R8_USCALED:
+               case VK_FORMAT_B8G8R8_SSCALED:
+               case VK_FORMAT_B8G8R8_UINT:
+               case VK_FORMAT_B8G8R8_SINT:
+               case VK_FORMAT_B8G8R8_SRGB:
+                       return 3;
+
+               case VK_FORMAT_R8G8B8A8_UNORM:
+               case VK_FORMAT_R8G8B8A8_SNORM:
+               case VK_FORMAT_R8G8B8A8_USCALED:
+               case VK_FORMAT_R8G8B8A8_SSCALED:
+               case VK_FORMAT_R8G8B8A8_UINT:
+               case VK_FORMAT_R8G8B8A8_SINT:
+               case VK_FORMAT_R8G8B8A8_SRGB:
+               case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+               case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+               case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+               case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+               case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+               case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+               case VK_FORMAT_R16G16_UNORM:
+               case VK_FORMAT_R16G16_SNORM:
+               case VK_FORMAT_R16G16_USCALED:
+               case VK_FORMAT_R16G16_SSCALED:
+               case VK_FORMAT_R16G16_UINT:
+               case VK_FORMAT_R16G16_SINT:
+               case VK_FORMAT_R16G16_SFLOAT:
+               case VK_FORMAT_R32_UINT:
+               case VK_FORMAT_R32_SINT:
+               case VK_FORMAT_R32_SFLOAT:
+               case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+               case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+               case VK_FORMAT_B8G8R8A8_UNORM:
+               case VK_FORMAT_B8G8R8A8_SNORM:
+               case VK_FORMAT_B8G8R8A8_USCALED:
+               case VK_FORMAT_B8G8R8A8_SSCALED:
+               case VK_FORMAT_B8G8R8A8_UINT:
+               case VK_FORMAT_B8G8R8A8_SINT:
+               case VK_FORMAT_B8G8R8A8_SRGB:
+               case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+               case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+                       return 4;
+
+               case VK_FORMAT_R16G16B16_UNORM:
+               case VK_FORMAT_R16G16B16_SNORM:
+               case VK_FORMAT_R16G16B16_USCALED:
+               case VK_FORMAT_R16G16B16_SSCALED:
+               case VK_FORMAT_R16G16B16_UINT:
+               case VK_FORMAT_R16G16B16_SINT:
+               case VK_FORMAT_R16G16B16_SFLOAT:
+                       return 6;
+
+               case VK_FORMAT_R16G16B16A16_UNORM:
+               case VK_FORMAT_R16G16B16A16_SNORM:
+               case VK_FORMAT_R16G16B16A16_USCALED:
+               case VK_FORMAT_R16G16B16A16_SSCALED:
+               case VK_FORMAT_R16G16B16A16_UINT:
+               case VK_FORMAT_R16G16B16A16_SINT:
+               case VK_FORMAT_R16G16B16A16_SFLOAT:
+               case VK_FORMAT_R32G32_UINT:
+               case VK_FORMAT_R32G32_SINT:
+               case VK_FORMAT_R32G32_SFLOAT:
+               case VK_FORMAT_R64_SFLOAT:
+                       return 8;
+
+               case VK_FORMAT_R32G32B32_UINT:
+               case VK_FORMAT_R32G32B32_SINT:
+               case VK_FORMAT_R32G32B32_SFLOAT:
+                       return 12;
+
+               case VK_FORMAT_R32G32B32A32_UINT:
+               case VK_FORMAT_R32G32B32A32_SINT:
+               case VK_FORMAT_R32G32B32A32_SFLOAT:
+               case VK_FORMAT_R64G64_SFLOAT:
+                       return 16;
+
+               case VK_FORMAT_R64G64B64_SFLOAT:
+                       return 24;
+
+               case VK_FORMAT_R64G64B64A64_SFLOAT:
+                       return 32;
+
+               default:
+                       break;
+       }
+
+       DE_ASSERT(false);
+       return 0;
+}
+
+deUint32 getVertexFormatComponentCount (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_USCALED:
+               case VK_FORMAT_R8_UNORM:
+               case VK_FORMAT_R8_UINT:
+               case VK_FORMAT_R8_SSCALED:
+               case VK_FORMAT_R8_SRGB:
+               case VK_FORMAT_R8_SNORM:
+               case VK_FORMAT_R8_SINT:
+               case VK_FORMAT_R16_USCALED:
+               case VK_FORMAT_R16_UNORM:
+               case VK_FORMAT_R16_UINT:
+               case VK_FORMAT_R16_SSCALED:
+               case VK_FORMAT_R16_SNORM:
+               case VK_FORMAT_R16_SINT:
+               case VK_FORMAT_R16_SFLOAT:
+               case VK_FORMAT_R32_UINT:
+               case VK_FORMAT_R32_SINT:
+               case VK_FORMAT_R32_SFLOAT:
+               case VK_FORMAT_R64_SFLOAT:
+                       return 1;
+
+               case VK_FORMAT_R4G4_UNORM_PACK8:
+               case VK_FORMAT_R8G8_UNORM:
+               case VK_FORMAT_R8G8_SNORM:
+               case VK_FORMAT_R8G8_USCALED:
+               case VK_FORMAT_R8G8_SSCALED:
+               case VK_FORMAT_R8G8_UINT:
+               case VK_FORMAT_R8G8_SINT:
+               case VK_FORMAT_R8G8_SRGB:
+               case VK_FORMAT_R16G16_UNORM:
+               case VK_FORMAT_R16G16_SNORM:
+               case VK_FORMAT_R16G16_USCALED:
+               case VK_FORMAT_R16G16_SSCALED:
+               case VK_FORMAT_R16G16_UINT:
+               case VK_FORMAT_R16G16_SINT:
+               case VK_FORMAT_R16G16_SFLOAT:
+               case VK_FORMAT_R32G32_UINT:
+               case VK_FORMAT_R32G32_SINT:
+               case VK_FORMAT_R32G32_SFLOAT:
+               case VK_FORMAT_R64G64_SFLOAT:
+                       return 2;
+
+               case VK_FORMAT_R8G8B8_UNORM:
+               case VK_FORMAT_R8G8B8_SNORM:
+               case VK_FORMAT_R8G8B8_USCALED:
+               case VK_FORMAT_R8G8B8_SSCALED:
+               case VK_FORMAT_R8G8B8_UINT:
+               case VK_FORMAT_R8G8B8_SINT:
+               case VK_FORMAT_R8G8B8_SRGB:
+               case VK_FORMAT_B8G8R8_UNORM:
+               case VK_FORMAT_B8G8R8_SNORM:
+               case VK_FORMAT_B8G8R8_USCALED:
+               case VK_FORMAT_B8G8R8_SSCALED:
+               case VK_FORMAT_B8G8R8_UINT:
+               case VK_FORMAT_B8G8R8_SINT:
+               case VK_FORMAT_B8G8R8_SRGB:
+               case VK_FORMAT_R16G16B16_UNORM:
+               case VK_FORMAT_R16G16B16_SNORM:
+               case VK_FORMAT_R16G16B16_USCALED:
+               case VK_FORMAT_R16G16B16_SSCALED:
+               case VK_FORMAT_R16G16B16_UINT:
+               case VK_FORMAT_R16G16B16_SINT:
+               case VK_FORMAT_R16G16B16_SFLOAT:
+               case VK_FORMAT_R32G32B32_UINT:
+               case VK_FORMAT_R32G32B32_SINT:
+               case VK_FORMAT_R32G32B32_SFLOAT:
+               case VK_FORMAT_R64G64B64_SFLOAT:
+               case VK_FORMAT_R5G6B5_UNORM_PACK16:
+               case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+               case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+                       return 3;
+
+               case VK_FORMAT_R8G8B8A8_UNORM:
+               case VK_FORMAT_R8G8B8A8_SNORM:
+               case VK_FORMAT_R8G8B8A8_USCALED:
+               case VK_FORMAT_R8G8B8A8_SSCALED:
+               case VK_FORMAT_R8G8B8A8_UINT:
+               case VK_FORMAT_R8G8B8A8_SINT:
+               case VK_FORMAT_R8G8B8A8_SRGB:
+               case VK_FORMAT_B8G8R8A8_UNORM:
+               case VK_FORMAT_B8G8R8A8_SNORM:
+               case VK_FORMAT_B8G8R8A8_USCALED:
+               case VK_FORMAT_B8G8R8A8_SSCALED:
+               case VK_FORMAT_B8G8R8A8_UINT:
+               case VK_FORMAT_B8G8R8A8_SINT:
+               case VK_FORMAT_B8G8R8A8_SRGB:
+               case VK_FORMAT_R16G16B16A16_UNORM:
+               case VK_FORMAT_R16G16B16A16_SNORM:
+               case VK_FORMAT_R16G16B16A16_USCALED:
+               case VK_FORMAT_R16G16B16A16_SSCALED:
+               case VK_FORMAT_R16G16B16A16_UINT:
+               case VK_FORMAT_R16G16B16A16_SINT:
+               case VK_FORMAT_R16G16B16A16_SFLOAT:
+               case VK_FORMAT_R32G32B32A32_UINT:
+               case VK_FORMAT_R32G32B32A32_SINT:
+               case VK_FORMAT_R32G32B32A32_SFLOAT:
+               case VK_FORMAT_R64G64B64A64_SFLOAT:
+               case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+               case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+               case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+               case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+               case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+               case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+               case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+               case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+               case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+                       return 4;
+
+               default:
+                       break;
+       }
+
+       DE_ASSERT(false);
+       return 0;
+}
+
+deUint32 getVertexFormatComponentSize (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_UNORM:
+               case VK_FORMAT_R8_SNORM:
+               case VK_FORMAT_R8_USCALED:
+               case VK_FORMAT_R8_SSCALED:
+               case VK_FORMAT_R8_UINT:
+               case VK_FORMAT_R8_SINT:
+               case VK_FORMAT_R8_SRGB:
+               case VK_FORMAT_R8G8_UNORM:
+               case VK_FORMAT_R8G8_SNORM:
+               case VK_FORMAT_R8G8_USCALED:
+               case VK_FORMAT_R8G8_SSCALED:
+               case VK_FORMAT_R8G8_UINT:
+               case VK_FORMAT_R8G8_SINT:
+               case VK_FORMAT_R8G8_SRGB:
+               case VK_FORMAT_R8G8B8_UNORM:
+               case VK_FORMAT_R8G8B8_SNORM:
+               case VK_FORMAT_R8G8B8_USCALED:
+               case VK_FORMAT_R8G8B8_SSCALED:
+               case VK_FORMAT_R8G8B8_UINT:
+               case VK_FORMAT_R8G8B8_SINT:
+               case VK_FORMAT_R8G8B8_SRGB:
+               case VK_FORMAT_B8G8R8_UNORM:
+               case VK_FORMAT_B8G8R8_SNORM:
+               case VK_FORMAT_B8G8R8_USCALED:
+               case VK_FORMAT_B8G8R8_SSCALED:
+               case VK_FORMAT_B8G8R8_UINT:
+               case VK_FORMAT_B8G8R8_SINT:
+               case VK_FORMAT_B8G8R8_SRGB:
+               case VK_FORMAT_R8G8B8A8_UNORM:
+               case VK_FORMAT_R8G8B8A8_SNORM:
+               case VK_FORMAT_R8G8B8A8_USCALED:
+               case VK_FORMAT_R8G8B8A8_SSCALED:
+               case VK_FORMAT_R8G8B8A8_UINT:
+               case VK_FORMAT_R8G8B8A8_SINT:
+               case VK_FORMAT_R8G8B8A8_SRGB:
+               case VK_FORMAT_B8G8R8A8_UNORM:
+               case VK_FORMAT_B8G8R8A8_SNORM:
+               case VK_FORMAT_B8G8R8A8_USCALED:
+               case VK_FORMAT_B8G8R8A8_SSCALED:
+               case VK_FORMAT_B8G8R8A8_UINT:
+               case VK_FORMAT_B8G8R8A8_SINT:
+               case VK_FORMAT_B8G8R8A8_SRGB:
+                       return 1;
+
+               case VK_FORMAT_R16_UNORM:
+               case VK_FORMAT_R16_SNORM:
+               case VK_FORMAT_R16_USCALED:
+               case VK_FORMAT_R16_SSCALED:
+               case VK_FORMAT_R16_UINT:
+               case VK_FORMAT_R16_SINT:
+               case VK_FORMAT_R16_SFLOAT:
+               case VK_FORMAT_R16G16_UNORM:
+               case VK_FORMAT_R16G16_SNORM:
+               case VK_FORMAT_R16G16_USCALED:
+               case VK_FORMAT_R16G16_SSCALED:
+               case VK_FORMAT_R16G16_UINT:
+               case VK_FORMAT_R16G16_SINT:
+               case VK_FORMAT_R16G16_SFLOAT:
+               case VK_FORMAT_R16G16B16_UNORM:
+               case VK_FORMAT_R16G16B16_SNORM:
+               case VK_FORMAT_R16G16B16_USCALED:
+               case VK_FORMAT_R16G16B16_SSCALED:
+               case VK_FORMAT_R16G16B16_UINT:
+               case VK_FORMAT_R16G16B16_SINT:
+               case VK_FORMAT_R16G16B16_SFLOAT:
+               case VK_FORMAT_R16G16B16A16_UNORM:
+               case VK_FORMAT_R16G16B16A16_SNORM:
+               case VK_FORMAT_R16G16B16A16_USCALED:
+               case VK_FORMAT_R16G16B16A16_SSCALED:
+               case VK_FORMAT_R16G16B16A16_UINT:
+               case VK_FORMAT_R16G16B16A16_SINT:
+               case VK_FORMAT_R16G16B16A16_SFLOAT:
+                       return 2;
+
+               case VK_FORMAT_R32_UINT:
+               case VK_FORMAT_R32_SINT:
+               case VK_FORMAT_R32_SFLOAT:
+               case VK_FORMAT_R32G32_UINT:
+               case VK_FORMAT_R32G32_SINT:
+               case VK_FORMAT_R32G32_SFLOAT:
+               case VK_FORMAT_R32G32B32_UINT:
+               case VK_FORMAT_R32G32B32_SINT:
+               case VK_FORMAT_R32G32B32_SFLOAT:
+               case VK_FORMAT_R32G32B32A32_UINT:
+               case VK_FORMAT_R32G32B32A32_SINT:
+               case VK_FORMAT_R32G32B32A32_SFLOAT:
+                       return 4;
+
+               case VK_FORMAT_R64_SFLOAT:
+               case VK_FORMAT_R64G64_SFLOAT:
+               case VK_FORMAT_R64G64B64_SFLOAT:
+               case VK_FORMAT_R64G64B64A64_SFLOAT:
+                       return 8;
+
+               default:
+                       break;
+       }
+
+       DE_ASSERT(false);
+       return 0;
+}
+
+bool isVertexFormatComponentOrderBGR (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_B8G8R8_UNORM:
+               case VK_FORMAT_B8G8R8_SNORM:
+               case VK_FORMAT_B8G8R8_USCALED:
+               case VK_FORMAT_B8G8R8_SSCALED:
+               case VK_FORMAT_B8G8R8_UINT:
+               case VK_FORMAT_B8G8R8_SINT:
+               case VK_FORMAT_B8G8R8_SRGB:
+               case VK_FORMAT_B8G8R8A8_UNORM:
+               case VK_FORMAT_B8G8R8A8_SNORM:
+               case VK_FORMAT_B8G8R8A8_USCALED:
+               case VK_FORMAT_B8G8R8A8_SSCALED:
+               case VK_FORMAT_B8G8R8A8_UINT:
+               case VK_FORMAT_B8G8R8A8_SINT:
+               case VK_FORMAT_B8G8R8A8_SRGB:
+               case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+               case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+               case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+               case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+                       return true;
+
+               default:
+                       break;
+       }
+       return false;
+}
+
+bool isVertexFormatSint (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_SINT:
+               case VK_FORMAT_R8G8_SINT:
+               case VK_FORMAT_R16_SINT:
+               case VK_FORMAT_R8G8B8_SINT:
+               case VK_FORMAT_B8G8R8_SINT:
+               case VK_FORMAT_R8G8B8A8_SINT:
+               case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+               case VK_FORMAT_R16G16_SINT:
+               case VK_FORMAT_R32_SINT:
+               case VK_FORMAT_B8G8R8A8_SINT:
+               case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+               case VK_FORMAT_R16G16B16_SINT:
+               case VK_FORMAT_R16G16B16A16_SINT:
+               case VK_FORMAT_R32G32_SINT:
+               case VK_FORMAT_R32G32B32_SINT:
+               case VK_FORMAT_R32G32B32A32_SINT:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+}
+
+bool isVertexFormatUint (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_UINT:
+               case VK_FORMAT_R8G8_UINT:
+               case VK_FORMAT_R16_UINT:
+               case VK_FORMAT_R8G8B8_UINT:
+               case VK_FORMAT_B8G8R8_UINT:
+               case VK_FORMAT_R8G8B8A8_UINT:
+               case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+               case VK_FORMAT_R16G16_UINT:
+               case VK_FORMAT_R32_UINT:
+               case VK_FORMAT_B8G8R8A8_UINT:
+               case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+               case VK_FORMAT_R16G16B16_UINT:
+               case VK_FORMAT_R16G16B16A16_UINT:
+               case VK_FORMAT_R32G32_UINT:
+               case VK_FORMAT_R32G32B32_UINT:
+               case VK_FORMAT_R32G32B32A32_UINT:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatSfloat (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R16_SFLOAT:
+               case VK_FORMAT_R16G16_SFLOAT:
+               case VK_FORMAT_R32_SFLOAT:
+               case VK_FORMAT_R16G16B16_SFLOAT:
+               case VK_FORMAT_R16G16B16A16_SFLOAT:
+               case VK_FORMAT_R32G32_SFLOAT:
+               case VK_FORMAT_R64_SFLOAT:
+               case VK_FORMAT_R32G32B32_SFLOAT:
+               case VK_FORMAT_R32G32B32A32_SFLOAT:
+               case VK_FORMAT_R64G64_SFLOAT:
+               case VK_FORMAT_R64G64B64_SFLOAT:
+               case VK_FORMAT_R64G64B64A64_SFLOAT:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatUfloat (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+               case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatUnorm (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_UNORM:
+               case VK_FORMAT_R4G4_UNORM_PACK8:
+               case VK_FORMAT_R8G8_UNORM:
+               case VK_FORMAT_R16_UNORM:
+               case VK_FORMAT_R5G6B5_UNORM_PACK16:
+               case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+               case VK_FORMAT_R8G8B8_UNORM:
+               case VK_FORMAT_B8G8R8_UNORM:
+               case VK_FORMAT_R8G8B8A8_UNORM:
+               case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+               case VK_FORMAT_R16G16_UNORM:
+               case VK_FORMAT_B8G8R8A8_UNORM:
+               case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+               case VK_FORMAT_R16G16B16_UNORM:
+               case VK_FORMAT_R16G16B16A16_UNORM:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatSnorm (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_SNORM:
+               case VK_FORMAT_R8G8_SNORM:
+               case VK_FORMAT_R16_SNORM:
+               case VK_FORMAT_R8G8B8_SNORM:
+               case VK_FORMAT_B8G8R8_SNORM:
+               case VK_FORMAT_R8G8B8A8_SNORM:
+               case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+               case VK_FORMAT_R16G16_SNORM:
+               case VK_FORMAT_B8G8R8A8_SNORM:
+               case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+               case VK_FORMAT_R16G16B16_SNORM:
+               case VK_FORMAT_R16G16B16A16_SNORM:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatSRGB (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_SRGB:
+               case VK_FORMAT_R8G8_SRGB:
+               case VK_FORMAT_R8G8B8_SRGB:
+               case VK_FORMAT_B8G8R8_SRGB:
+               case VK_FORMAT_R8G8B8A8_SRGB:
+               case VK_FORMAT_B8G8R8A8_SRGB:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatSscaled (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_SSCALED:
+               case VK_FORMAT_R8G8_SSCALED:
+               case VK_FORMAT_R16_SSCALED:
+               case VK_FORMAT_R8G8B8_SSCALED:
+               case VK_FORMAT_B8G8R8_SSCALED:
+               case VK_FORMAT_R8G8B8A8_SSCALED:
+               case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+               case VK_FORMAT_R16G16_SSCALED:
+               case VK_FORMAT_B8G8R8A8_SSCALED:
+               case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+               case VK_FORMAT_R16G16B16_SSCALED:
+               case VK_FORMAT_R16G16B16A16_SSCALED:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
+bool isVertexFormatUscaled (VkFormat format)
+{
+       switch (format)
+       {
+               case VK_FORMAT_R8_USCALED:
+               case VK_FORMAT_R8G8_USCALED:
+               case VK_FORMAT_R16_USCALED:
+               case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
+               case VK_FORMAT_R8G8B8_USCALED:
+               case VK_FORMAT_B8G8R8_USCALED:
+               case VK_FORMAT_R8G8B8A8_USCALED:
+               case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+               case VK_FORMAT_R16G16_USCALED:
+               case VK_FORMAT_B8G8R8A8_USCALED:
+               case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+               case VK_FORMAT_R16G16B16_USCALED:
+               case VK_FORMAT_R16G16B16A16_USCALED:
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+
+}
+
 std::vector<Vertex4RGBA> createOverlappingQuads (void)
 {
        using tcu::Vec2;
index 35cc913..4e76f48 100644 (file)
@@ -58,6 +58,20 @@ struct Vertex4Tex4
        tcu::Vec4 texCoord;
 };
 
+deUint32                                       getVertexFormatSize                             (vk::VkFormat format);
+deUint32                                       getVertexFormatComponentCount   (vk::VkFormat format);
+deUint32                                       getVertexFormatComponentSize    (vk::VkFormat format);
+bool                                           isVertexFormatComponentOrderBGR (vk::VkFormat format);
+bool                                           isVertexFormatSint                              (vk::VkFormat format);
+bool                                           isVertexFormatUint                              (vk::VkFormat format);
+bool                                           isVertexFormatSfloat                    (vk::VkFormat format);
+bool                                           isVertexFormatUfloat                    (vk::VkFormat format);
+bool                                           isVertexFormatUnorm                             (vk::VkFormat format);
+bool                                           isVertexFormatSnorm                             (vk::VkFormat format);
+bool                                           isVertexFormatSRGB                              (vk::VkFormat format);
+bool                                           isVertexFormatSscaled                   (vk::VkFormat format);
+bool                                           isVertexFormatUscaled                   (vk::VkFormat format);
+
 /*! \brief Creates a pattern of 4 overlapping quads.
  *
  *  The quads are alined along the plane Z = 0, with X,Y taking values between -1 and 1.
index 1de8f24..819b6a3 100644 (file)
@@ -4373,13 +4373,13 @@ public:
                                                                                                                                                 const  CaseContext                             caseCtx,
                                                                                                                                                 ShaderExecutor&                                executor,
                                                                                                                                                 const  Variables<In, Out>              variables,
-                                                                                                                                                const  Inputs<In>                              inputs,
+                                                                                                                                                const  Samplings<In>&                  samplings,
                                                                                                                                                 const  StatementP                              stmt)
                                                                                : TestInstance  (context)
                                                                                , m_caseCtx     (caseCtx)
                                                                                , m_executor    (executor)
                                                                                , m_variables   (variables)
-                                                                               , m_inputs              (inputs)
+                                                                               , m_samplings   (samplings)
                                                                                , m_stmt                (stmt)
                                                                        {
                                                                        }
@@ -4389,7 +4389,7 @@ protected:
        CaseContext                                             m_caseCtx;
        ShaderExecutor&                                 m_executor;
        Variables<In, Out>                              m_variables;
-       Inputs<In>                                              m_inputs;
+       const Samplings<In>&                    m_samplings;
        StatementP                                              m_stmt;
 };
 
@@ -4403,10 +4403,11 @@ tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
        typedef typename        Out::Out0       Out0;
        typedef typename        Out::Out1       Out1;
 
+       Inputs<In>                      inputs          = generateInputs(m_samplings, m_caseCtx.floatFormat, m_caseCtx.precision, m_caseCtx.numRandoms, 0xdeadbeefu + m_caseCtx.testContext.getCommandLine().getBaseSeed());
        const FloatFormat&      fmt                     = m_caseCtx.floatFormat;
        const int                       inCount         = numInputs<In>();
        const int                       outCount        = numOutputs<Out>();
-       const size_t            numValues       = (inCount > 0) ? m_inputs.in0.size() : 1;
+       const size_t            numValues       = (inCount > 0) ? inputs.in0.size() : 1;
        Outputs<Out>            outputs         (numValues);
        const FloatFormat       highpFmt        = m_caseCtx.highpFormat;
        const int                       maxMsgs         = 100;
@@ -4417,13 +4418,22 @@ tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
 
        const void*             inputArr[]      =
        {
-               &m_inputs.in0.front(), &m_inputs.in1.front(), &m_inputs.in2.front(), &m_inputs.in3.front(),
+               &inputs.in0.front(), &inputs.in1.front(), &inputs.in2.front(), &inputs.in3.front(),
        };
        void*                           outputArr[]     =
        {
                &outputs.out0.front(), &outputs.out1.front(),
        };
 
+       switch (inCount)
+       {
+               case 4: DE_ASSERT(inputs.in3.size() == numValues);
+               case 3: DE_ASSERT(inputs.in2.size() == numValues);
+               case 2: DE_ASSERT(inputs.in1.size() == numValues);
+               case 1: DE_ASSERT(inputs.in0.size() == numValues);
+               default: break;
+       }
+
        m_executor.execute(m_context, int(numValues), inputArr, outputArr);
 
        // Initialize environment with dummy values so we don't need to bind in inner loop.
@@ -4451,10 +4461,10 @@ tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
                typename Traits<Out0>::IVal     reference0;
                typename Traits<Out1>::IVal     reference1;
 
-               env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, m_inputs.in0[valueNdx]));
-               env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, m_inputs.in1[valueNdx]));
-               env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, m_inputs.in2[valueNdx]));
-               env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, m_inputs.in3[valueNdx]));
+               env.lookup(*m_variables.in0) = convert<In0>(fmt, round(fmt, inputs.in0[valueNdx]));
+               env.lookup(*m_variables.in1) = convert<In1>(fmt, round(fmt, inputs.in1[valueNdx]));
+               env.lookup(*m_variables.in2) = convert<In2>(fmt, round(fmt, inputs.in2[valueNdx]));
+               env.lookup(*m_variables.in3) = convert<In3>(fmt, round(fmt, inputs.in3[valueNdx]));
 
                {
                        EvalContext     ctx (fmt, m_caseCtx.precision, env);
@@ -4488,25 +4498,25 @@ tcu::TestStatus BuiltinPrecisionCaseTestInstance<In, Out>::iterate (void)
                        if (inCount > 0)
                        {
                                builder << "\t" << m_variables.in0->getName() << " = "
-                                               << valueToString(highpFmt, m_inputs.in0[valueNdx]) << "\n";
+                                               << valueToString(highpFmt, inputs.in0[valueNdx]) << "\n";
                        }
 
                        if (inCount > 1)
                        {
                                builder << "\t" << m_variables.in1->getName() << " = "
-                                               << valueToString(highpFmt, m_inputs.in1[valueNdx]) << "\n";
+                                               << valueToString(highpFmt, inputs.in1[valueNdx]) << "\n";
                        }
 
                        if (inCount > 2)
                        {
                                builder << "\t" << m_variables.in2->getName() << " = "
-                                               << valueToString(highpFmt, m_inputs.in2[valueNdx]) << "\n";
+                                               << valueToString(highpFmt, inputs.in2[valueNdx]) << "\n";
                        }
 
                        if (inCount > 3)
                        {
                                builder << "\t" << m_variables.in3->getName() << " = "
-                                               << valueToString(highpFmt, m_inputs.in3[valueNdx]) << "\n";
+                                               << valueToString(highpFmt, inputs.in3[valueNdx]) << "\n";
                        }
 
                        if (outCount > 0)
@@ -4561,7 +4571,6 @@ protected:
                                                PrecisionCase   (const CaseContext& context, const string& name, const string& extension = "")
                                                        : TestCase              (context.testContext, name.c_str(), name.c_str())
                                                        , m_ctx                 (context)
-                                                       , m_rnd                 (0xdeadbeefu + context.testContext.getCommandLine().getBaseSeed())
                                                        , m_extension   (extension)
                                                        , m_executor    (DE_NULL)
                                                        {
@@ -4576,7 +4585,7 @@ protected:
        TestLog&                        log                             (void) const                    { return m_testCtx.getLog(); }
 
        template <typename In, typename Out>
-       void                            testStatement   (const Variables<In, Out>& variables, const Inputs<In>& inputs, const Statement& stmt);
+       void                            testStatement   (const Variables<In, Out>& variables, const Statement& stmt);
 
        template<typename T>
        Symbol                          makeSymbol              (const Variable<T>& variable)
@@ -4585,30 +4594,18 @@ protected:
        }
 
        CaseContext                                                     m_ctx;
-       Random                                                          m_rnd;
        const string                                            m_extension;
        ShaderSpec                                                      m_spec;
        de::MovePtr<ShaderExecutor>                     m_executor;
 };
 
 template <typename In, typename Out>
-void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Inputs<In>& inputs, const Statement& stmt)
+void PrecisionCase::testStatement (const Variables<In, Out>& variables, const Statement& stmt)
 {
        const int               inCount         = numInputs<In>();
        const int               outCount        = numOutputs<Out>();
-       const size_t    numValues       = (inCount > 0) ? inputs.in0.size() : 1;
-       Outputs<Out>    outputs         (numValues);
        Environment             env;            // Hoisted out of the inner loop for optimization.
 
-       switch (inCount)
-       {
-               case 4: DE_ASSERT(inputs.in3.size() == numValues);
-               case 3: DE_ASSERT(inputs.in2.size() == numValues);
-               case 2: DE_ASSERT(inputs.in1.size() == numValues);
-               case 1: DE_ASSERT(inputs.in0.size() == numValues);
-               default: break;
-       }
-
        // Print out the statement and its definitions
        log() << TestLog::Message << "Statement: " << stmt << TestLog::EndMessage;
        {
@@ -4763,8 +4760,9 @@ Inputs<In> generateInputs (const Samplings<In>&   samplings,
                                                   const FloatFormat&   floatFormat,
                                                   Precision                    intPrecision,
                                                   size_t                               numSamples,
-                                                  Random&                              rnd)
+                                                  deUint32                             seed)
 {
+       Random                                                                          rnd(seed);
        Inputs<In>                                                                      ret;
        Inputs<In>                                                                      fixedInputs;
        set<InTuple<In>, InputLess<InTuple<In> > >      seenInputs;
@@ -4851,12 +4849,12 @@ public:
 
        virtual TestInstance*                                   createInstance  (Context& context) const
        {
-               return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, m_inputs, m_stmt);
+               return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
        }
 
 protected:
        void                                                                    buildTest               (void);
-       virtual const Samplings<In>&                    getSamplings    (void)
+       virtual const Samplings<In>&                    getSamplings    (void) const
        {
                return instance<DefaultSamplings<In> >();
        }
@@ -4864,14 +4862,11 @@ protected:
 private:
        const CaseFunc&                                                 m_func;
        Variables<In, Out>                                              m_variables;
-       Inputs<In>                                                              m_inputs;
 };
 
 template <typename Sig>
 void FuncCase<Sig>::buildTest (void)
 {
-       m_inputs                        = generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd);
-
        m_variables.out0        = variable<Ret>("out0");
        m_variables.out1        = variable<Void>("out1");
        m_variables.in0         = variable<Arg0>("in0");
@@ -4883,7 +4878,7 @@ void FuncCase<Sig>::buildTest (void)
                ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.in1, m_variables.in2, m_variables.in3);
                m_stmt                  = variableAssignment(m_variables.out0, expr);
 
-               this->testStatement(m_variables, m_inputs, *m_stmt);
+               this->testStatement(m_variables, *m_stmt);
        }
 }
 
@@ -4908,24 +4903,24 @@ public:
                                                                                        }
        virtual TestInstance*                           createInstance  (Context& context) const
        {
-               return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, m_inputs, m_stmt);
+               return new BuiltinPrecisionCaseTestInstance<In, Out>(context, m_ctx, *m_executor, m_variables, getSamplings(), m_stmt);
        }
 
 protected:
        void                                                            buildTest               (void);
-
-       virtual const Samplings<In>&            getSamplings    (void)  { return instance<DefaultSamplings<In> >();     }
+       virtual const Samplings<In>&            getSamplings    (void) const
+       {
+               return instance<DefaultSamplings<In> >();
+       }
 
 private:
        const CaseFunc&                                         m_func;
        Variables<In, Out>                                      m_variables;
-       Inputs<In>                                                      m_inputs;
 };
 
 template <typename Sig>
 void InOutFuncCase<Sig>::buildTest (void)
 {
-       m_inputs                        = generateInputs(getSamplings(), m_ctx.floatFormat, m_ctx.precision, m_ctx.numRandoms, m_rnd);
 
        m_variables.out0        = variable<Ret>("out0");
        m_variables.out1        = variable<Arg1>("out1");
@@ -4938,7 +4933,7 @@ void InOutFuncCase<Sig>::buildTest (void)
                ExprP<Ret> expr = applyVar(m_func, m_variables.in0, m_variables.out1, m_variables.in1, m_variables.in2);
                m_stmt                  = variableAssignment(m_variables.out0, expr);
 
-               this->testStatement(m_variables, m_inputs, *m_stmt);
+               this->testStatement(m_variables, *m_stmt);
        }
 }
 
index 2d7249e..a51e250 100644 (file)
@@ -659,7 +659,7 @@ void FragmentOutExecutor::addAttribute (const Context& ctx, Allocator& memAlloc,
        de::MovePtr<Allocation> alloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
        VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset()));
 
-       deMemcpy(alloc->getHostPtr(), dataPtr, inputSize);
+       deMemcpy(alloc->getHostPtr(), dataPtr, (size_t)inputSize);
        flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), inputSize);
 
        m_vertexBuffers.push_back(de::SharedPtr<Unique<VkBuffer> >(new Unique<VkBuffer>(buffer)));
@@ -1064,6 +1064,19 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void
                        1.0f                                                                                                                    // float                                                                                lineWidth;
                };
 
+               const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                                   // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
+                       VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
+               };
+               
                const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
                {
                        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,               // VkStructureType                                                              sType;
@@ -1097,7 +1110,7 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void
                        DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
                        &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
                        &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
-                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
                        DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
                        &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
                        &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
@@ -2563,6 +2576,19 @@ void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount)
                        1.0f                                                                                                                    // float                                                                        lineWidth;
                };
 
+               const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                                   // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
+                       VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
+               };
+
                const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
                {
                        VK_FALSE,                                               // VkBool32                                     blendEnable;
@@ -2611,7 +2637,7 @@ void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount)
                        &tessellationStateParams,                                                       // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
                        &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
                        &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
-                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
                        DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
                        &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
                        &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
index 6e062fb..f2213e2 100644 (file)
@@ -542,13 +542,9 @@ void ShaderRenderCaseInstance::setupUniformData (deUint32 bindingLocation, size_
        deMemcpy(alloc->getHostPtr(), dataPtr, size);
        flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), size);
 
-       // \todo [2015-10-09 elecro] remove the 'hackPadding' variable if the driver support small uniforms,
-       // that is for example one float big uniforms.
-       const size_t hackPadding = size < 4 * sizeof(float) ? 3 * sizeof(float) : 0;
-
        de::MovePtr<BufferUniform> uniformInfo(new BufferUniform());
        uniformInfo->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
-       uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size + hackPadding);
+       uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size);
        uniformInfo->location = bindingLocation;
        uniformInfo->buffer = VkBufferSp(new vk::Unique<VkBuffer>(buffer));
        uniformInfo->alloc = AllocationSp(alloc.release());
@@ -1422,7 +1418,7 @@ void ShaderRenderCaseInstance::render (tcu::Surface& result, const QuadGrid& qua
                        false,                                                                                                                  // VkBool32                     rasterizerDiscardEnable;
                        VK_POLYGON_MODE_FILL,                                                                                   // VkFillMode           fillMode;
                        VK_CULL_MODE_NONE,                                                                                              // VkCullMode           cullMode;
-                       VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                        // VkFrontFace          frontFace;
+                       VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace          frontFace;
                        false,                                                                                                                  // VkBool32                     depthBiasEnable;
                        0.0f,                                                                                                                   // float                        depthBias;
                        0.0f,                                                                                                                   // float                        depthBiasClamp;
@@ -1430,6 +1426,19 @@ void ShaderRenderCaseInstance::render (tcu::Surface& result, const QuadGrid& qua
                        1.0f,                                                                                                                   // float                        lineWidth;
                };
 
+               const VkPipelineMultisampleStateCreateInfo              multisampleStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       0u,                                                                                                                             // VkPipelineMultisampleStateCreateFlags        flags;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
+                       0.0f,                                                                                                                   // float                                                                        minSampleShading;
+                       DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
+                       VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
+               };
+               
                const VkPipelineColorBlendAttachmentState               colorBlendAttachmentState       =
                {
                        false,                                                                                                                  // VkBool32                     blendEnable;
@@ -1478,7 +1487,7 @@ void ShaderRenderCaseInstance::render (tcu::Surface& result, const QuadGrid& qua
                        DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
                        &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
                        &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
-                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       &multisampleStateParams,                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
                        DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
                        &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
                        &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
index 2d325f3..711e525 100644 (file)
@@ -1756,7 +1756,7 @@ void ShaderMatrixCase::setupShader (void)
        }
 
        static const std::string header =
-               "#version 140\n"
+               "#version 310 es\n"
                "#extension GL_ARB_separate_shader_objects : enable\n"
                "#extension GL_ARB_shading_language_420pack : enable\n";
 
index 23872a5..8bb83e5 100644 (file)
@@ -48,10 +48,11 @@ namespace
 using namespace vk;
 using std::vector;
 
-typedef de::MovePtr<Allocation>                        AllocationMp;
-typedef de::SharedPtr<Allocation>              AllocationSp;
-typedef Unique<VkBuffer>                               BufferHandleUp;
-typedef de::SharedPtr<BufferHandleUp>  BufferHandleSp;
+typedef vkt::SpirVAssembly::AllocationMp                       AllocationMp;
+typedef vkt::SpirVAssembly::AllocationSp                       AllocationSp;
+
+typedef Unique<VkBuffer>                                                       BufferHandleUp;
+typedef de::SharedPtr<BufferHandleUp>                          BufferHandleSp;
 
 /*--------------------------------------------------------------------*//*!
  * \brief Create storage buffer, allocate and bind memory for the buffer
@@ -91,11 +92,11 @@ void setMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation*
        flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
 }
 
-void clearMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes)
+void fillMemoryWithValue (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes, deUint8 value)
 {
        void* const hostPtr = destAlloc->getHostPtr();
 
-       deMemset((deUint8*)hostPtr, 0, numBytes);
+       deMemset((deUint8*)hostPtr, value, numBytes);
        flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
 }
 
@@ -177,17 +178,38 @@ Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const Vk
 /*--------------------------------------------------------------------*//*!
  * \brief Create a compute pipeline based on the given shader
  *//*--------------------------------------------------------------------*/
-Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShaderModule shader)
+Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShaderModule shader, const char* entryPoint, const vector<deUint32>& specConstants)
 {
+       const deUint32                                                  numSpecConstants                                = (deUint32)specConstants.size();
+       vector<VkSpecializationMapEntry>                entries;
+       VkSpecializationInfo                                    specInfo;
+
+       if (numSpecConstants != 0)
+       {
+               entries.reserve(numSpecConstants);
+
+               for (deUint32 ndx = 0; ndx < numSpecConstants; ++ndx)
+               {
+                       entries[ndx].constantID = ndx;
+                       entries[ndx].offset             = ndx * (deUint32)sizeof(deUint32);
+                       entries[ndx].size               = sizeof(deUint32);
+               }
+
+               specInfo.mapEntryCount          = numSpecConstants;
+               specInfo.pMapEntries            = &entries[0];
+               specInfo.dataSize                       = numSpecConstants * sizeof(deUint32);
+               specInfo.pData                          = specConstants.data();
+       }
+
        const VkPipelineShaderStageCreateInfo   pipelineShaderStageCreateInfo   =
        {
                VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // sType
                DE_NULL,                                                                                                // pNext
-               (VkPipelineShaderStageCreateFlags)0,
+               (VkPipelineShaderStageCreateFlags)0,                                    // flags
                VK_SHADER_STAGE_COMPUTE_BIT,                                                    // stage
-               shader,                                                                                                 // shader
-               "main",
-               DE_NULL,                                                                                                // pSpecializationInfo
+               shader,                                                                                                 // module
+               entryPoint,                                                                                             // pName
+               (numSpecConstants == 0) ? DE_NULL : &specInfo,                  // pSpecializationInfo
        };
        const VkComputePipelineCreateInfo               pipelineCreateInfo                              =
        {
@@ -313,7 +335,7 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
                const size_t            numBytes        = output->getNumBytes();
                BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
 
-               clearMemory(vkdi, device, &*alloc, numBytes);
+               fillMemoryWithValue(vkdi, device, &*alloc, numBytes, 0xff);
                descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
                outputBuffers.push_back(BufferHandleSp(buffer));
                outputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
@@ -331,7 +353,7 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
        const ProgramBinary&                            binary                          = m_context.getBinaryCollection().get("compute");
        Unique<VkShaderModule>                          module                          (createShaderModule(vkdi, device, binary, (VkShaderModuleCreateFlags)0u));
 
-       Unique<VkPipeline>                                      computePipeline         (createComputePipeline(vkdi, device, *pipelineLayout, *module));
+       Unique<VkPipeline>                                      computePipeline         (createComputePipeline(vkdi, device, *pipelineLayout, *module, m_shaderSpec.entryPoint.c_str(), m_shaderSpec.specConstants));
 
        // Create command buffer and record commands
 
@@ -394,13 +416,20 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
        VK_CHECK(vkdi.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
 
        // Check output.
-
-       for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+       if (m_shaderSpec.verifyIO)
        {
-               const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
-               if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
+               if (!(*m_shaderSpec.verifyIO)(m_shaderSpec.inputs, outputAllocs, m_shaderSpec.outputs))
                        return tcu::TestStatus::fail("Output doesn't match with expected");
        }
+       else
+       {
+               for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+               {
+                       const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
+                       if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
+                               return tcu::TestStatus::fail("Output doesn't match with expected");
+               }
+       }
 
        return tcu::TestStatus::pass("Ouput match with expected");
 }
index fbfa5c0..d4703b9 100644 (file)
@@ -37,6 +37,7 @@
 #include "deDefs.h"
 #include "deSharedPtr.hpp"
 #include "tcuVector.hpp"
+#include "vkMemUtil.hpp"
 
 #include <string>
 #include <vector>
@@ -46,6 +47,9 @@ namespace vkt
 namespace SpirVAssembly
 {
 
+typedef de::MovePtr<vk::Allocation>                    AllocationMp;
+typedef de::SharedPtr<vk::Allocation>          AllocationSp;
+
 /*--------------------------------------------------------------------*//*!
  * \brief Abstract class for an input/output storage buffer object
  *//*--------------------------------------------------------------------*/
@@ -78,7 +82,11 @@ private:
        std::vector<E>          m_elements;
 };
 
-typedef Buffer<float>  Float32Buffer;
+DE_STATIC_ASSERT(sizeof(tcu::Vec4) == 4 * sizeof(float));
+
+typedef Buffer<float>          Float32Buffer;
+typedef Buffer<deInt32>                Int32Buffer;
+typedef Buffer<tcu::Vec4>      Vec4Buffer;
 
 
 /*--------------------------------------------------------------------*//*!
@@ -90,9 +98,22 @@ typedef Buffer<float>        Float32Buffer;
 struct ComputeShaderSpec
 {
        std::string                             assembly;
+       std::string                             entryPoint;
        std::vector<BufferSp>   inputs;
        std::vector<BufferSp>   outputs;
        tcu::IVec3                              numWorkGroups;
+       std::vector<deUint32>   specConstants;
+       // If null, a default verification will be performed by comparing the memory pointed to by outputAllocations
+       // and the contents of expectedOutputs. Otherwise the function pointed to by verifyIO will be called.
+       // If true is returned, then the test case is assumed to have passed, if false is returned, then the test
+       // case is assumed to have failed.
+       bool                                    (*verifyIO)(const std::vector<BufferSp>& inputs, const std::vector<AllocationSp>& outputAllocations, const std::vector<BufferSp>& expectedOutputs);
+
+                                                       ComputeShaderSpec()
+                                                               : entryPoint    ("main")
+                                                               , verifyIO              (DE_NULL)
+                                                       {}
+
 };
 
 } // SpirVAssembly
index 56f74cf..440eb25 100644 (file)
 #include "deUniquePtr.hpp"
 #include "tcuStringTemplate.hpp"
 
+#include <cmath>
 #include "vktSpvAsmComputeShaderCase.hpp"
 #include "vktSpvAsmComputeShaderTestUtil.hpp"
 #include "vktTestCaseUtil.hpp"
 
+#include <cmath>
+#include <limits>
 #include <map>
 #include <string>
 #include <sstream>
@@ -85,6 +88,7 @@ using tcu::TestStatus;
 using tcu::Vec4;
 using de::UniquePtr;
 using tcu::StringTemplate;
+using tcu::Vec4;
 
 typedef Unique<VkShaderModule>                 ModuleHandleUp;
 typedef de::SharedPtr<ModuleHandleUp>  ModuleHandleSp;
@@ -92,7 +96,6 @@ typedef de::SharedPtr<ModuleHandleUp> ModuleHandleSp;
 template<typename T>   T                       randomScalar    (de::Random& rnd, T minValue, T maxValue);
 template<> inline              float           randomScalar    (de::Random& rnd, float minValue, float maxValue)               { return rnd.getFloat(minValue, maxValue);      }
 template<> inline              deInt32         randomScalar    (de::Random& rnd, deInt32 minValue, deInt32 maxValue)   { return rnd.getInt(minValue, maxValue);        }
-template<> inline              deUint32        randomScalar    (de::Random& rnd, deUint32 minValue, deUint32 maxValue) { return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
 
 template<typename T>
 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
@@ -102,6 +105,14 @@ static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* ds
                typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
 }
 
+struct CaseParameter
+{
+       const char*             name;
+       string                  param;
+
+       CaseParameter   (const char* case_, const string& param_) : name(case_), param(param_) {}
+};
+
 // Assembly code used for testing OpNop, OpConstant{Null|Composite}, Op[No]Line, OpSource[Continued], OpSourceExtension, OpUndef is based on GLSL source code:
 //
 // #version 430
@@ -121,9 +132,9 @@ static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* ds
 // }
 
 static const char* const s_ShaderPreamble =
-               "OpCapability Shader\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint GLCompute %main \"main\" %id\n"
+       "OpCapability Shader\n"
+       "OpMemoryModel Logical GLSL450\n"
+       "OpEntryPoint GLCompute %main \"main\" %id\n"
        "OpExecutionMode %main LocalSize 1 1 1\n";
 
 static const char* const s_CommonTypes =
@@ -150,14 +161,14 @@ static const char* const s_InputOutputBuffer =
 // Declares buffer type and layout for uniform variables indata and outdata. Both of them are SSBO bounded to descriptor set 0.
 // indata is at binding point 0, while outdata is at 1.
 static const char* const s_InputOutputBufferTraits =
-               "OpDecorate %inbuf BufferBlock\n"
-               "OpDecorate %indata DescriptorSet 0\n"
-               "OpDecorate %indata Binding 0\n"
-               "OpDecorate %outbuf BufferBlock\n"
-               "OpDecorate %outdata DescriptorSet 0\n"
-               "OpDecorate %outdata Binding 1\n"
-               "OpDecorate %f32arr ArrayStride 4\n"
-               "OpMemberDecorate %inbuf 0 Offset 0\n"
+       "OpDecorate %inbuf BufferBlock\n"
+       "OpDecorate %indata DescriptorSet 0\n"
+       "OpDecorate %indata Binding 0\n"
+       "OpDecorate %outbuf BufferBlock\n"
+       "OpDecorate %outdata DescriptorSet 0\n"
+       "OpDecorate %outdata Binding 1\n"
+       "OpDecorate %f32arr ArrayStride 4\n"
+       "OpMemberDecorate %inbuf 0 Offset 0\n"
        "OpMemberDecorate %outbuf 0 Offset 0\n";
 
 tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
@@ -343,6 +354,384 @@ tcu::TestCaseGroup* createOpNoLineGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
+tcu::TestCaseGroup* createNoContractionGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
+       vector<CaseParameter>                   cases;
+       const int                                               numElements             = 100;
+       vector<float>                                   inputFloats1    (numElements, 0);
+       vector<float>                                   inputFloats2    (numElements, 0);
+       vector<float>                                   outputFloats    (numElements, 0);
+       const StringTemplate                    shaderTemplate  (
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               "${DECORATION}\n"
+
+               "OpDecorate %inbuf1 BufferBlock\n"
+               "OpDecorate %indata1 DescriptorSet 0\n"
+               "OpDecorate %indata1 Binding 0\n"
+               "OpDecorate %inbuf2 BufferBlock\n"
+               "OpDecorate %indata2 DescriptorSet 0\n"
+               "OpDecorate %indata2 Binding 1\n"
+               "OpDecorate %outbuf BufferBlock\n"
+               "OpDecorate %outdata DescriptorSet 0\n"
+               "OpDecorate %outdata Binding 2\n"
+               "OpDecorate %f32arr ArrayStride 4\n"
+               "OpMemberDecorate %inbuf1 0 Offset 0\n"
+               "OpMemberDecorate %inbuf2 0 Offset 0\n"
+               "OpMemberDecorate %outbuf 0 Offset 0\n"
+
+               + string(s_CommonTypes) +
+
+               "%inbuf1     = OpTypeStruct %f32arr\n"
+               "%inbufptr1  = OpTypePointer Uniform %inbuf1\n"
+               "%indata1    = OpVariable %inbufptr1 Uniform\n"
+               "%inbuf2     = OpTypeStruct %f32arr\n"
+               "%inbufptr2  = OpTypePointer Uniform %inbuf2\n"
+               "%indata2    = OpVariable %inbufptr2 Uniform\n"
+               "%outbuf     = OpTypeStruct %f32arr\n"
+               "%outbufptr  = OpTypePointer Uniform %outbuf\n"
+               "%outdata    = OpVariable %outbufptr Uniform\n"
+
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%zero       = OpConstant %i32 0\n"
+               "%c_f_m1     = OpConstant %f32 -1.\n"
+
+               "%main       = OpFunction %void None %voidf\n"
+               "%label      = OpLabel\n"
+               "%idval      = OpLoad %uvec3 %id\n"
+               "%x          = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc1     = OpAccessChain %f32ptr %indata1 %zero %x\n"
+               "%inval1     = OpLoad %f32 %inloc1\n"
+               "%inloc2     = OpAccessChain %f32ptr %indata2 %zero %x\n"
+               "%inval2     = OpLoad %f32 %inloc2\n"
+               "%mul        = OpFMul %f32 %inval1 %inval2\n"
+               "%add        = OpFAdd %f32 %mul %c_f_m1\n"
+               "%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "              OpStore %outloc %add\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n");
+
+       cases.push_back(CaseParameter("multiplication", "OpDecorate %mul NoContraction"));
+       cases.push_back(CaseParameter("addition",               "OpDecorate %add NoContraction"));
+       cases.push_back(CaseParameter("both",                   "OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"));
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+       {
+               inputFloats1[ndx]       = 1.f + std::ldexp(1.f, -23); // 1 + 2^-23.
+               inputFloats2[ndx]       = 1.f - std::ldexp(1.f, -23); // 1 - 2^-23.
+               // Result for (1 + 2^-23) * (1 - 2^-23) - 1. With NoContraction, the multiplication will be
+               // conducted separately and the result is rounded to 1. So the final result will be 0.f.
+               // If the operation is combined into a precise fused multiply-add, then the result would be
+               // 2^-46 (0xa8800000).
+               outputFloats[ndx]       = 0.f;
+       }
+
+       for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+       {
+               map<string, string>             specializations;
+               ComputeShaderSpec               spec;
+
+               specializations["DECORATION"] = cases[caseNdx].param;
+               spec.assembly = shaderTemplate.specialize(specializations);
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
+       }
+       return group.release();
+}
+
+// Copy contents in the input buffer to the output buffer.
+tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opcopymemory", "Test the OpCopyMemory instruction"));
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+       const int                                               numElements             = 100;
+
+       // The following case adds vec4(0., 0.5, 1.5, 2.5) to each of the elements in the input buffer and writes output to the output buffer.
+       ComputeShaderSpec                               spec1;
+       vector<Vec4>                                    inputFloats1    (numElements);
+       vector<Vec4>                                    outputFloats1   (numElements);
+
+       fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+               outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
+
+       spec1.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%vec4       = OpTypeVector %f32 4\n"
+               "%vec4ptr_u  = OpTypePointer Uniform %vec4\n"
+               "%vec4ptr_f  = OpTypePointer Function %vec4\n"
+               "%vec4arr    = OpTypeRuntimeArray %vec4\n"
+               "%inbuf      = OpTypeStruct %vec4arr\n"
+               "%inbufptr   = OpTypePointer Uniform %inbuf\n"
+               "%indata     = OpVariable %inbufptr Uniform\n"
+               "%outbuf     = OpTypeStruct %vec4arr\n"
+               "%outbufptr  = OpTypePointer Uniform %outbuf\n"
+               "%outdata    = OpVariable %outbufptr Uniform\n"
+
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%zero       = OpConstant %i32 0\n"
+               "%c_f_0      = OpConstant %f32 0.\n"
+               "%c_f_0_5    = OpConstant %f32 0.5\n"
+               "%c_f_1_5    = OpConstant %f32 1.5\n"
+               "%c_f_2_5    = OpConstant %f32 2.5\n"
+               "%c_vec4     = OpConstantComposite %vec4 %c_f_0 %c_f_0_5 %c_f_1_5 %c_f_2_5\n"
+
+               "%main       = OpFunction %void None %voidf\n"
+               "%label      = OpLabel\n"
+               "%v_vec4     = OpVariable %vec4ptr_f Function\n"
+               "%idval      = OpLoad %uvec3 %id\n"
+               "%x          = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc      = OpAccessChain %vec4ptr_u %indata %zero %x\n"
+               "%outloc     = OpAccessChain %vec4ptr_u %outdata %zero %x\n"
+               "              OpCopyMemory %v_vec4 %inloc\n"
+               "%v_vec4_val = OpLoad %vec4 %v_vec4\n"
+               "%add        = OpFAdd %vec4 %v_vec4_val %c_vec4\n"
+               "              OpStore %outloc %add\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n";
+
+       spec1.inputs.push_back(BufferSp(new Vec4Buffer(inputFloats1)));
+       spec1.outputs.push_back(BufferSp(new Vec4Buffer(outputFloats1)));
+       spec1.numWorkGroups = IVec3(numElements, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector", "OpCopyMemory elements of vector type", spec1));
+
+       // The following case copies a float[100] variable from the input buffer to the output buffer.
+       ComputeShaderSpec                               spec2;
+       vector<float>                                   inputFloats2    (numElements);
+       vector<float>                                   outputFloats2   (numElements);
+
+       fillRandomScalars(rnd, -200.f, 200.f, &inputFloats2[0], numElements);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+               outputFloats2[ndx] = inputFloats2[ndx];
+
+       spec2.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%hundred        = OpConstant %u32 100\n"
+               "%f32arr100      = OpTypeArray %f32 %hundred\n"
+               "%f32arr100ptr_f = OpTypePointer Function %f32arr100\n"
+               "%f32arr100ptr_u = OpTypePointer Uniform %f32arr100\n"
+               "%inbuf          = OpTypeStruct %f32arr100\n"
+               "%inbufptr       = OpTypePointer Uniform %inbuf\n"
+               "%indata         = OpVariable %inbufptr Uniform\n"
+               "%outbuf         = OpTypeStruct %f32arr100\n"
+               "%outbufptr      = OpTypePointer Uniform %outbuf\n"
+               "%outdata        = OpVariable %outbufptr Uniform\n"
+
+               "%id             = OpVariable %uvec3ptr Input\n"
+               "%zero           = OpConstant %i32 0\n"
+
+               "%main           = OpFunction %void None %voidf\n"
+               "%label          = OpLabel\n"
+               "%var            = OpVariable %f32arr100ptr_f Function\n"
+               "%inarr          = OpAccessChain %f32arr100ptr_u %indata %zero\n"
+               "%outarr         = OpAccessChain %f32arr100ptr_u %outdata %zero\n"
+               "                  OpCopyMemory %var %inarr\n"
+               "                  OpCopyMemory %outarr %var\n"
+               "                  OpReturn\n"
+               "                  OpFunctionEnd\n";
+
+       spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
+       spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+       spec2.numWorkGroups = IVec3(1, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "array", "OpCopyMemory elements of array type", spec2));
+
+       // The following case copies a struct{vec4, vec4, vec4, vec4} variable from the input buffer to the output buffer.
+       ComputeShaderSpec                               spec3;
+       vector<float>                                   inputFloats3    (16);
+       vector<float>                                   outputFloats3   (16);
+
+       fillRandomScalars(rnd, -200.f, 200.f, &inputFloats3[0], 16);
+
+       for (size_t ndx = 0; ndx < 16; ++ndx)
+               outputFloats3[ndx] = -inputFloats3[ndx];
+
+       spec3.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%vec4      = OpTypeVector %f32 4\n"
+               "%inbuf     = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
+               "%inbufptr  = OpTypePointer Uniform %inbuf\n"
+               "%indata    = OpVariable %inbufptr Uniform\n"
+               "%outbuf    = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
+               "%outbufptr = OpTypePointer Uniform %outbuf\n"
+               "%outdata   = OpVariable %outbufptr Uniform\n"
+               "%vec4stptr = OpTypePointer Function %inbuf\n"
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%var       = OpVariable %vec4stptr Function\n"
+               "             OpCopyMemory %var %indata\n"
+               "             OpCopyMemory %outdata %var\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n";
+
+       spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats3)));
+       spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
+       spec3.numWorkGroups = IVec3(1, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "struct", "OpCopyMemory elements of struct type", spec3));
+
+       // The following case negates multiple float variables from the input buffer and stores the results to the output buffer.
+       ComputeShaderSpec                               spec4;
+       vector<float>                                   inputFloats4    (numElements);
+       vector<float>                                   outputFloats4   (numElements);
+
+       fillRandomScalars(rnd, -200.f, 200.f, &inputFloats4[0], numElements);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+               outputFloats4[ndx] = -inputFloats4[ndx];
+
+       spec4.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%f32ptr_f  = OpTypePointer Function %f32\n"
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%var       = OpVariable %f32ptr_f Function\n"
+               "%idval     = OpLoad %uvec3 %id\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
+               "%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "             OpCopyMemory %var %inloc\n"
+               "%val       = OpLoad %f32 %var\n"
+               "%neg       = OpFNegate %f32 %val\n"
+               "             OpStore %outloc %neg\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n";
+
+       spec4.inputs.push_back(BufferSp(new Float32Buffer(inputFloats4)));
+       spec4.outputs.push_back(BufferSp(new Float32Buffer(outputFloats4)));
+       spec4.numWorkGroups = IVec3(numElements, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "float", "OpCopyMemory elements of float type", spec4));
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createOpCopyObjectGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opcopyobject", "Test the OpCopyObject instruction"));
+       ComputeShaderSpec                               spec;
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+       const int                                               numElements             = 100;
+       vector<float>                                   inputFloats             (numElements, 0);
+       vector<float>                                   outputFloats    (numElements, 0);
+
+       fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+               outputFloats[ndx] = inputFloats[ndx] + 7.5f;
+
+       spec.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%fvec3    = OpTypeVector %f32 3\n"
+               "%fmat     = OpTypeMatrix %fvec3 3\n"
+               "%three    = OpConstant %u32 3\n"
+               "%farr     = OpTypeArray %f32 %three\n"
+               "%fst      = OpTypeStruct %f32 %f32\n"
+
+               + string(s_InputOutputBuffer) +
+
+               "%id            = OpVariable %uvec3ptr Input\n"
+               "%zero          = OpConstant %i32 0\n"
+               "%c_f           = OpConstant %f32 1.5\n"
+               "%c_fvec3       = OpConstantComposite %fvec3 %c_f %c_f %c_f\n"
+               "%c_fmat        = OpConstantComposite %fmat %c_fvec3 %c_fvec3 %c_fvec3\n"
+               "%c_farr        = OpConstantComposite %farr %c_f %c_f %c_f\n"
+               "%c_fst         = OpConstantComposite %fst %c_f %c_f\n"
+
+               "%main          = OpFunction %void None %voidf\n"
+               "%label         = OpLabel\n"
+               "%c_f_copy      = OpCopyObject %f32   %c_f\n"
+               "%c_fvec3_copy  = OpCopyObject %fvec3 %c_fvec3\n"
+               "%c_fmat_copy   = OpCopyObject %fmat  %c_fmat\n"
+               "%c_farr_copy   = OpCopyObject %farr  %c_farr\n"
+               "%c_fst_copy    = OpCopyObject %fst   %c_fst\n"
+               "%fvec3_elem    = OpCompositeExtract %f32 %c_fvec3_copy 0\n"
+               "%fmat_elem     = OpCompositeExtract %f32 %c_fmat_copy 1 2\n"
+               "%farr_elem     = OpCompositeExtract %f32 %c_fmat_copy 2\n"
+               "%fst_elem      = OpCompositeExtract %f32 %c_fmat_copy 1\n"
+               // Add up. 1.5 * 5 = 7.5.
+               "%add1          = OpFAdd %f32 %c_f_copy %fvec3_elem\n"
+               "%add2          = OpFAdd %f32 %add1     %fmat_elem\n"
+               "%add3          = OpFAdd %f32 %add2     %farr_elem\n"
+               "%add4          = OpFAdd %f32 %add3     %fst_elem\n"
+
+               "%idval         = OpLoad %uvec3 %id\n"
+               "%x             = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc         = OpAccessChain %f32ptr %indata %zero %x\n"
+               "%outloc        = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "%inval         = OpLoad %f32 %inloc\n"
+               "%add           = OpFAdd %f32 %add4 %inval\n"
+               "                 OpStore %outloc %add\n"
+               "                 OpReturn\n"
+               "                 OpFunctionEnd\n";
+       spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+       spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "spotcheck", "OpCopyObject on different types", spec));
+
+       return group.release();
+}
 // Assembly code used for testing OpUnreachable is based on GLSL source code:
 //
 // #version 430
@@ -655,14 +1044,240 @@ tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
+struct SpecConstantTwoIntCase
+{
+       const char*             caseName;
+       const char*             scDefinition0;
+       const char*             scDefinition1;
+       const char*             scResultType;
+       const char*             scOperation;
+       deInt32                 scActualValue0;
+       deInt32                 scActualValue1;
+       const char*             resultOperation;
+       vector<deInt32> expectedOutput;
+
+                                       SpecConstantTwoIntCase (const char* name,
+                                                                                       const char* definition0,
+                                                                                       const char* definition1,
+                                                                                       const char* resultType,
+                                                                                       const char* operation,
+                                                                                       deInt32 value0,
+                                                                                       deInt32 value1,
+                                                                                       const char* resultOp,
+                                                                                       const vector<deInt32>& output)
+                                               : caseName                      (name)
+                                               , scDefinition0         (definition0)
+                                               , scDefinition1         (definition1)
+                                               , scResultType          (resultType)
+                                               , scOperation           (operation)
+                                               , scActualValue0        (value0)
+                                               , scActualValue1        (value1)
+                                               , resultOperation       (resultOp)
+                                               , expectedOutput        (output) {}
+};
+
+tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
+       vector<SpecConstantTwoIntCase>  cases;
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+       const int                                               numElements             = 100;
+       vector<deInt32>                                 inputInts               (numElements, 0);
+       vector<deInt32>                                 outputInts1             (numElements, 0);
+       vector<deInt32>                                 outputInts2             (numElements, 0);
+       vector<deInt32>                                 outputInts3             (numElements, 0);
+       vector<deInt32>                                 outputInts4             (numElements, 0);
+       vector<deInt32>                                 outputInts5             (numElements, 0);
+       const StringTemplate                    shaderTemplate  (
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+               "OpDecorate %sc_0  SpecId 0\n"
+               "OpDecorate %sc_1  SpecId 1\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%i32ptr    = OpTypePointer Uniform %i32\n"
+               "%i32arr    = OpTypeRuntimeArray %i32\n"
+               "%boolptr   = OpTypePointer Uniform %bool\n"
+               "%boolarr   = OpTypeRuntimeArray %bool\n"
+               "%inbuf     = OpTypeStruct %i32arr\n"
+               "%inbufptr  = OpTypePointer Uniform %inbuf\n"
+               "%indata    = OpVariable %inbufptr Uniform\n"
+               "%outbuf    = OpTypeStruct %i32arr\n"
+               "%outbufptr = OpTypePointer Uniform %outbuf\n"
+               "%outdata   = OpVariable %outbufptr Uniform\n"
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+
+               "%sc_0      = OpSpecConstant${SC_DEF0}\n"
+               "%sc_1      = OpSpecConstant${SC_DEF1}\n"
+               "%sc_final  = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%idval     = OpLoad %uvec3 %id\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc     = OpAccessChain %i32ptr %indata %zero %x\n"
+               "%inval     = OpLoad %i32 %inloc\n"
+               "%final     = ${GEN_RESULT}\n"
+               "%outloc    = OpAccessChain %i32ptr %outdata %zero %x\n"
+               "             OpStore %outloc %final\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n");
+
+       fillRandomScalars(rnd, -65536, 65536, &inputInts[0], numElements);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+       {
+               outputInts1[ndx] = inputInts[ndx] + 42;
+               outputInts2[ndx] = inputInts[ndx];
+               outputInts3[ndx] = inputInts[ndx] - 11200;
+               outputInts4[ndx] = inputInts[ndx] + 1;
+               outputInts5[ndx] = inputInts[ndx] - 2;
+       }
+
+       const char addScToInput[]               = "OpIAdd %i32 %inval %sc_final";
+       const char selectTrueUsingSc[]  = "OpSelect %i32 %sc_final %inval %zero";
+       const char selectFalseUsingSc[] = "OpSelect %i32 %sc_final %zero %inval";
+
+       cases.push_back(SpecConstantTwoIntCase("iadd",                                  " %i32 0",              " %i32 0",              "%i32",         "IAdd                 %sc_0 %sc_1",                     62,             -20,    addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("isub",                                  " %i32 0",              " %i32 0",              "%i32",         "ISub                 %sc_0 %sc_1",                     100,    58,             addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("imul",                                  " %i32 0",              " %i32 0",              "%i32",         "IMul                 %sc_0 %sc_1",                     -2,             -21,    addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("sdiv",                                  " %i32 0",              " %i32 0",              "%i32",         "SDiv                 %sc_0 %sc_1",                     -126,   -3,             addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("udiv",                                  " %i32 0",              " %i32 0",              "%i32",         "UDiv                 %sc_0 %sc_1",                     126,    3,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("srem",                                  " %i32 0",              " %i32 0",              "%i32",         "SRem                 %sc_0 %sc_1",                     7,              -3,             addScToInput,           outputInts4));
+       cases.push_back(SpecConstantTwoIntCase("smod",                                  " %i32 0",              " %i32 0",              "%i32",         "SMod                 %sc_0 %sc_1",                     7,              -3,             addScToInput,           outputInts5));
+       cases.push_back(SpecConstantTwoIntCase("umod",                                  " %i32 0",              " %i32 0",              "%i32",         "UMod                 %sc_0 %sc_1",                     342,    50,             addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("bitwiseand",                    " %i32 0",              " %i32 0",              "%i32",         "BitwiseAnd           %sc_0 %sc_1",                     42,             63,             addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("bitwiseor",                             " %i32 0",              " %i32 0",              "%i32",         "BitwiseOr            %sc_0 %sc_1",                     34,             8,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("bitwisexor",                    " %i32 0",              " %i32 0",              "%i32",         "BitwiseAnd           %sc_0 %sc_1",                     18,             56,             addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("shiftrightlogical",             " %i32 0",              " %i32 0",              "%i32",         "ShiftRightLogical    %sc_0 %sc_1",                     168,    2,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("shiftrightarithmetic",  " %i32 0",              " %i32 0",              "%i32",         "ShiftRightArithmetic %sc_0 %sc_1",                     168,    2,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("shiftleftlogical",              " %i32 0",              " %i32 0",              "%i32",         "ShiftLeftLogical     %sc_0 %sc_1",                     21,             1,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("slessthan",                             " %i32 0",              " %i32 0",              "%bool",        "SLessThan            %sc_0 %sc_1",                     -20,    -10,    selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("ulessthan",                             " %i32 0",              " %i32 0",              "%bool",        "ULessThan            %sc_0 %sc_1",                     10,             20,             selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("sgreaterthan",                  " %i32 0",              " %i32 0",              "%bool",        "SGreaterThan         %sc_0 %sc_1",                     -1000,  50,             selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("ugreaterthan",                  " %i32 0",              " %i32 0",              "%bool",        "UGreaterThan         %sc_0 %sc_1",                     10,             5,              selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("slessthanequal",                " %i32 0",              " %i32 0",              "%bool",        "SLessThanEqual       %sc_0 %sc_1",                     -10,    -10,    selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("ulessthanequal",                " %i32 0",              " %i32 0",              "%bool",        "ULessThanEqual       %sc_0 %sc_1",                     50,             100,    selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("sgreaterthanequal",             " %i32 0",              " %i32 0",              "%bool",        "SGreaterThanEqual    %sc_0 %sc_1",                     -1000,  50,             selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("ugreaterthanequal",             " %i32 0",              " %i32 0",              "%bool",        "UGreaterThanEqual    %sc_0 %sc_1",                     10,             10,             selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("iequal",                                " %i32 0",              " %i32 0",              "%bool",        "IEqual               %sc_0 %sc_1",                     42,             24,             selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("logicaland",                    "True %bool",   "True %bool",   "%bool",        "LogicalAnd           %sc_0 %sc_1",                     0,              1,              selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("logicalor",                             "False %bool",  "False %bool",  "%bool",        "LogicalOr            %sc_0 %sc_1",                     1,              0,              selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("logicalequal",                  "True %bool",   "True %bool",   "%bool",        "LogicalEqual         %sc_0 %sc_1",                     0,              1,              selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("logicalnotequal",               "False %bool",  "False %bool",  "%bool",        "LogicalNotEqual      %sc_0 %sc_1",                     1,              0,              selectTrueUsingSc,      outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("snegate",                               " %i32 0",              " %i32 0",              "%i32",         "SNegate              %sc_0",                           -42,    0,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("not",                                   " %i32 0",              " %i32 0",              "%i32",         "Not                  %sc_0",                           -43,    0,              addScToInput,           outputInts1));
+       cases.push_back(SpecConstantTwoIntCase("logicalnot",                    "False %bool",  "False %bool",  "%bool",        "LogicalNot           %sc_0",                           1,              0,              selectFalseUsingSc,     outputInts2));
+       cases.push_back(SpecConstantTwoIntCase("select",                                "False %bool",  " %i32 0",              "%i32",         "Select               %sc_0 %sc_1 %zero",       1,              42,             addScToInput,           outputInts1));
+       // OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
+
+       for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+       {
+               map<string, string>             specializations;
+               ComputeShaderSpec               spec;
+
+               specializations["SC_DEF0"]                      = cases[caseNdx].scDefinition0;
+               specializations["SC_DEF1"]                      = cases[caseNdx].scDefinition1;
+               specializations["SC_RESULT_TYPE"]       = cases[caseNdx].scResultType;
+               specializations["SC_OP"]                        = cases[caseNdx].scOperation;
+               specializations["GEN_RESULT"]           = cases[caseNdx].resultOperation;
+
+               spec.assembly = shaderTemplate.specialize(specializations);
+               spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
+               spec.outputs.push_back(BufferSp(new Int32Buffer(cases[caseNdx].expectedOutput)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+               spec.specConstants.push_back(cases[caseNdx].scActualValue0);
+               spec.specConstants.push_back(cases[caseNdx].scActualValue1);
+
+               group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].caseName, cases[caseNdx].caseName, spec));
+       }
+
+       ComputeShaderSpec                               spec;
+
+       spec.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+               "OpDecorate %sc_0  SpecId 0\n"
+               "OpDecorate %sc_1  SpecId 1\n"
+               "OpDecorate %sc_2  SpecId 2\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+
+               "%ivec3     = OpTypeVector %i32 3\n"
+               "%i32ptr    = OpTypePointer Uniform %i32\n"
+               "%i32arr    = OpTypeRuntimeArray %i32\n"
+               "%boolptr   = OpTypePointer Uniform %bool\n"
+               "%boolarr   = OpTypeRuntimeArray %bool\n"
+               "%inbuf     = OpTypeStruct %i32arr\n"
+               "%inbufptr  = OpTypePointer Uniform %inbuf\n"
+               "%indata    = OpVariable %inbufptr Uniform\n"
+               "%outbuf    = OpTypeStruct %i32arr\n"
+               "%outbufptr = OpTypePointer Uniform %outbuf\n"
+               "%outdata   = OpVariable %outbufptr Uniform\n"
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+               "%ivec3_0   = OpConstantComposite %ivec3 %zero %zero %zero\n"
+
+               "%sc_0        = OpSpecConstant %i32 0\n"
+               "%sc_1        = OpSpecConstant %i32 0\n"
+               "%sc_2        = OpSpecConstant %i32 0\n"
+               "%sc_vec3_0   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_0        %ivec3_0   0\n"     // (sc_0, 0, 0)
+               "%sc_vec3_1   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_1        %ivec3_0   1\n"     // (0, sc_1, 0)
+               "%sc_vec3_2   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_2        %ivec3_0   2\n"     // (0, 0, sc_2)
+               "%sc_vec3_01  = OpSpecConstantOp %ivec3 VectorShuffle    %sc_vec3_0   %sc_vec3_1 1 0 4\n" // (0,    sc_0, sc_1)
+               "%sc_vec3_012 = OpSpecConstantOp %ivec3 VectorShuffle    %sc_vec3_01  %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
+               "%sc_ext_0    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            0\n"     // sc_2
+               "%sc_ext_1    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            1\n"     // sc_0
+               "%sc_ext_2    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            2\n"     // sc_1
+               "%sc_sub      = OpSpecConstantOp %i32   ISub             %sc_ext_0    %sc_ext_1\n"        // (sc_2 - sc_0)
+               "%sc_final    = OpSpecConstantOp %i32   IMul             %sc_sub      %sc_ext_2\n"        // (sc_2 - sc_0) * sc_1
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%idval     = OpLoad %uvec3 %id\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc     = OpAccessChain %i32ptr %indata %zero %x\n"
+               "%inval     = OpLoad %i32 %inloc\n"
+               "%final     = OpIAdd %i32 %inval %sc_final\n"
+               "%outloc    = OpAccessChain %i32ptr %outdata %zero %x\n"
+               "             OpStore %outloc %final\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n";
+       spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
+       spec.outputs.push_back(BufferSp(new Int32Buffer(outputInts3)));
+       spec.numWorkGroups = IVec3(numElements, 1, 1);
+       spec.specConstants.push_back(123);
+       spec.specConstants.push_back(56);
+       spec.specConstants.push_back(-77);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector_related", "VectorShuffle, CompositeExtract, & CompositeInsert", spec));
+
+       return group.release();
+}
 tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
-       ComputeShaderSpec                               spec;
+       ComputeShaderSpec                               spec1;
+       ComputeShaderSpec                               spec2;
+       ComputeShaderSpec                               spec3;
        de::Random                                              rnd                             (deStringHash(group->getName()));
        const int                                               numElements             = 100;
        vector<float>                                   inputFloats             (numElements, 0);
-       vector<float>                                   outputFloats    (numElements, 0);
+       vector<float>                                   outputFloats1   (numElements, 0);
+       vector<float>                                   outputFloats2   (numElements, 0);
+       vector<float>                                   outputFloats3   (numElements, 0);
 
        fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
 
@@ -670,14 +1285,16 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
        {
                switch (ndx % 3)
                {
-                       case 0:         outputFloats[ndx] = inputFloats[ndx] + 5.5f;    break;
-                       case 1:         outputFloats[ndx] = inputFloats[ndx] + 20.5f;   break;
-                       case 2:         outputFloats[ndx] = inputFloats[ndx] + 1.75f;   break;
+                       case 0:         outputFloats1[ndx] = inputFloats[ndx] + 5.5f;   break;
+                       case 1:         outputFloats1[ndx] = inputFloats[ndx] + 20.5f;  break;
+                       case 2:         outputFloats1[ndx] = inputFloats[ndx] + 1.75f;  break;
                        default:        break;
                }
+               outputFloats2[ndx] = inputFloats[ndx] + 6.5f * 3;
+               outputFloats3[ndx] = 8.5f - inputFloats[ndx];
        }
 
-       spec.assembly =
+       spec1.assembly =
                string(s_ShaderPreamble) +
 
                "OpSource GLSL 430\n"
@@ -731,16 +1348,106 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
                "            OpBranch %phi\n"
 
                "            OpFunctionEnd\n";
-       spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
-       spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
-       spec.numWorkGroups = IVec3(numElements, 1, 1);
+       spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
+       spec1.numWorkGroups = IVec3(numElements, 1, 1);
 
-       group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpPhi corner cases", spec));
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "block", "out-of-order and unreachable blocks for OpPhi", spec1));
 
-       return group.release();
-}
+       spec2.assembly =
+               string(s_ShaderPreamble) +
 
-// Assembly code used for testing block order is based on GLSL source code:
+               "OpName %main \"main\"\n"
+               "OpName %id \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%zero       = OpConstant %i32 0\n"
+               "%one        = OpConstant %i32 1\n"
+               "%three      = OpConstant %i32 3\n"
+               "%constf6p5  = OpConstant %f32 6.5\n"
+
+               "%main       = OpFunction %void None %voidf\n"
+               "%entry      = OpLabel\n"
+               "%idval      = OpLoad %uvec3 %id\n"
+               "%x          = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc      = OpAccessChain %f32ptr %indata %zero %x\n"
+               "%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "%inval      = OpLoad %f32 %inloc\n"
+               "              OpBranch %phi\n"
+
+               "%phi        = OpLabel\n"
+               "%step       = OpPhi %i32 %zero  %entry %step_next  %phi\n"
+               "%accum      = OpPhi %f32 %inval %entry %accum_next %phi\n"
+               "%step_next  = OpIAdd %i32 %step %one\n"
+               "%accum_next = OpFAdd %f32 %accum %constf6p5\n"
+               "%still_loop = OpSLessThan %bool %step %three\n"
+               "              OpLoopMerge %exit %phi None\n"
+               "              OpBranchConditional %still_loop %phi %exit\n"
+
+               "%exit       = OpLabel\n"
+               "              OpStore %outloc %accum\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n";
+       spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+       spec2.numWorkGroups = IVec3(numElements, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "induction", "The usual way induction variables are handled in LLVM IR", spec2));
+
+       spec3.assembly =
+               string(s_ShaderPreamble) +
+
+               "OpName %main \"main\"\n"
+               "OpName %id \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%f32ptr_f   = OpTypePointer Function %f32\n"
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%true       = OpConstantTrue %bool\n"
+               "%false      = OpConstantFalse %bool\n"
+               "%zero       = OpConstant %i32 0\n"
+               "%constf8p5  = OpConstant %f32 8.5\n"
+
+               "%main       = OpFunction %void None %voidf\n"
+               "%entry      = OpLabel\n"
+               "%b          = OpVariable %f32ptr_f Function %constf8p5\n"
+               "%idval      = OpLoad %uvec3 %id\n"
+               "%x          = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc      = OpAccessChain %f32ptr %indata %zero %x\n"
+               "%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "%a_init     = OpLoad %f32 %inloc\n"
+               "%b_init     = OpLoad %f32 %b\n"
+               "              OpBranch %phi\n"
+
+               "%phi        = OpLabel\n"
+               "%still_loop = OpPhi %bool %true   %entry %false  %phi\n"
+               "%a_next     = OpPhi %f32  %a_init %entry %b_next %phi\n"
+               "%b_next     = OpPhi %f32  %b_init %entry %a_next %phi\n"
+               "              OpLoopMerge %exit %phi None\n"
+               "              OpBranchConditional %still_loop %phi %exit\n"
+
+               "%exit       = OpLabel\n"
+               "%sub        = OpFSub %f32 %a_next %b_next\n"
+               "              OpStore %outloc %sub\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n";
+       spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
+       spec3.numWorkGroups = IVec3(numElements, 1, 1);
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "swap", "Swap the values of two variables using OpPhi", spec3));
+
+       return group.release();
+}
+
+// Assembly code used for testing block order is based on GLSL source code:
 //
 // #version 430
 //
@@ -898,13 +1605,138 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
-struct CaseParameter
+tcu::TestCaseGroup* createMultipleShaderGroup (tcu::TestContext& testCtx)
 {
-       const char*             name;
-       string                  param;
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "multiple_shaders", "Test multiple shaders in the same module"));
+       ComputeShaderSpec                               spec1;
+       ComputeShaderSpec                               spec2;
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+       const int                                               numElements             = 100;
+       vector<float>                                   inputFloats             (numElements, 0);
+       vector<float>                                   outputFloats1   (numElements, 0);
+       vector<float>                                   outputFloats2   (numElements, 0);
+       fillRandomScalars(rnd, -500.f, 500.f, &inputFloats[0], numElements);
 
-       CaseParameter   (const char* case_, const string& param_) : name(case_), param(param_) {}
-};
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+       {
+               outputFloats1[ndx] = inputFloats[ndx] + inputFloats[ndx];
+               outputFloats2[ndx] = -inputFloats[ndx];
+       }
+
+       const string assembly =
+               "OpCapability Shader\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint GLCompute %comp_main1 \"entrypoint1\" %id\n"
+               "OpEntryPoint GLCompute %comp_main2 \"entrypoint2\" %id\n"
+               // A module cannot have two OpEntryPoint instructions with the same Execution Model and the same Name string.
+               "OpEntryPoint Vertex    %vert_main  \"entrypoint2\" %vert_builtins %vertexID %instanceID\n"
+               "OpExecutionMode %main LocalSize 1 1 1\n";
+
+               "OpName %comp_main1              \"entrypoint1\"\n"
+               "OpName %comp_main2              \"entrypoint2\"\n"
+               "OpName %vert_main               \"entrypoint2\"\n"
+               "OpName %id                      \"gl_GlobalInvocationID\"\n"
+               "OpName %vert_builtin_st         \"gl_PerVertex\"\n"
+               "OpName %vertexID                \"gl_VertexID\"\n"
+               "OpName %instanceID              \"gl_InstanceID\"\n"
+               "OpMemberName %vert_builtin_st 0 \"gl_Position\"\n"
+               "OpMemberName %vert_builtin_st 1 \"gl_PointSize\"\n"
+               "OpMemberName %vert_builtin_st 2 \"gl_ClipDistance\"\n"
+
+               "OpDecorate %id                      BuiltIn GlobalInvocationId\n"
+               "OpDecorate %vertexID                BuiltIn VertexId\n"
+               "OpDecorate %instanceID              BuiltIn InstanceId\n"
+               "OpDecorate %vert_builtin_st         Block\n"
+               "OpMemberDecorate %vert_builtin_st 0 BuiltIn Position\n"
+               "OpMemberDecorate %vert_builtin_st 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %vert_builtin_st 2 BuiltIn ClipDistance\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%i32ptr              = OpTypePointer Input %i32\n"
+               "%vec4                = OpTypeVector %f32 4\n"
+               "%vec4ptr             = OpTypePointer Output %vec4\n"
+               "%f32arr1             = OpTypeArray %f32 %one\n"
+               "%vert_builtin_st     = OpTypeStruct %vec4 %f32 %f32arr1\n"
+               "%vert_builtin_st_ptr = OpTypePointer Output %vert_builtin_st\n"
+               "%vert_builtins       = OpVariable %vert_builtin_st_ptr Output\n"
+
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%vertexID   = OpVariable %i32ptr Input\n"
+               "%instanceID = OpVariable %i32ptr Input\n"
+               "%zero       = OpConstant %i32 0\n"
+               "%one        = OpConstant %u32 1\n"
+               "%c_f32_1    = OpConstant %f32 1\n"
+               "%c_vec4_1   = OpConstantComposite %vec4 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+
+               // gl_Position = vec4(1.);
+               "%vert_main  = OpFunction %void None %voidf\n"
+               "%vert_entry = OpLabel\n"
+               "%position   = OpAccessChain %vec4ptr %vert_builtins %zero\n"
+               "              OpStore %position %c_vec4_1\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n"
+
+               // Double inputs.
+               "%comp_main1  = OpFunction %void None %voidf\n"
+               "%comp1_entry = OpLabel\n"
+               "%idval1      = OpLoad %uvec3 %id\n"
+               "%x1          = OpCompositeExtract %u32 %idval1 0\n"
+               "%inloc1      = OpAccessChain %f32ptr %indata %zero %x1\n"
+               "%inval1      = OpLoad %f32 %inloc1\n"
+               "%add         = OpFAdd %f32 %inval1 %inval1\n"
+               "%outloc1     = OpAccessChain %f32ptr %outdata %zero %x1\n"
+               "               OpStore %outloc1 %add\n"
+               "               OpReturn\n"
+               "               OpFunctionEnd\n"
+
+               // Negate inputs.
+               "%comp_main2  = OpFunction %void None %voidf\n"
+               "%comp2_entry = OpLabel\n"
+               "%idval2      = OpLoad %uvec3 %id\n"
+               "%x2          = OpCompositeExtract %u32 %idval2 0\n"
+               "%inloc2      = OpAccessChain %f32ptr %indata %zero %x2\n"
+               "%inval2      = OpLoad %f32 %inloc2\n"
+               "%neg         = OpFNegate %f32 %inval2\n"
+               "%outloc2     = OpAccessChain %f32ptr %outdata %zero %x2\n"
+               "               OpStore %outloc2 %neg\n"
+               "               OpReturn\n"
+               "               OpFunctionEnd\n";
+
+       spec1.assembly = assembly;
+       spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
+       spec1.numWorkGroups = IVec3(numElements, 1, 1);
+       spec1.entryPoint = "entrypoint1";
+
+       spec2.assembly = assembly;
+       spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+       spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
+       spec2.numWorkGroups = IVec3(numElements, 1, 1);
+       spec2.entryPoint = "entrypoint2";
+
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader1", "multiple shaders in the same module", spec1));
+       group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader2", "multiple shaders in the same module", spec2));
+
+       return group.release();
+}
+
+inline std::string makeLongUTF8String (size_t num4ByteChars)
+{
+       // An example of a longest valid UTF-8 character.  Be explicit about the
+       // character type because Microsoft compilers can otherwise interpret the
+       // character string as being over wide (16-bit) characters. Ideally, we
+       // would just use a C++11 UTF-8 string literal, but we want to support older
+       // Microsoft compilers.
+       const std::basic_string<char> earthAfrica("\xF0\x9F\x8C\x8D");
+       std::string longString;
+       longString.reserve(num4ByteChars * 4);
+       for (size_t count = 0; count < num4ByteChars; count++)
+       {
+               longString += earthAfrica;
+       }
+       return longString;
+}
 
 tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
 {
@@ -956,7 +1788,7 @@ tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
        cases.push_back(CaseParameter("empty_source_code",                                              "%fname = OpString \"filename\"\n"
                                                                                                                                                        "OpSource GLSL 430 %fname \"\""));
        cases.push_back(CaseParameter("long_source_code",                                               "%fname = OpString \"filename\"\n"
-                                                                                                                                                       "OpSource GLSL 430 %fname \"" + string(65530, 'x') + "\"")); // word count: 65535
+                                                                                                                                                       "OpSource GLSL 430 %fname \"" + makeLongUTF8String(65530) + "ccc\"")); // word count: 65535
        cases.push_back(CaseParameter("utf8_source_code",                                               "%fname = OpString \"filename\"\n"
                                                                                                                                                        "OpSource GLSL 430 %fname \"\xE2\x98\x82\xE2\x98\x85\"")); // umbrella & black star symbol
        cases.push_back(CaseParameter("normal_sourcecontinued",                                 "%fname = OpString \"filename\"\n"
@@ -967,7 +1799,7 @@ tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
                                                                                                                                                        "OpSourceContinued \"\""));
        cases.push_back(CaseParameter("long_sourcecontinued",                                   "%fname = OpString \"filename\"\n"
                                                                                                                                                        "OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
-                                                                                                                                                       "OpSourceContinued \"" + string(65533, 'x') + "\"")); // word count: 65535
+                                                                                                                                                       "OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\"")); // word count: 65535
        cases.push_back(CaseParameter("utf8_sourcecontinued",                                   "%fname = OpString \"filename\"\n"
                                                                                                                                                        "OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
                                                                                                                                                        "OpSourceContinued \"\xE2\x98\x8E\xE2\x9A\x91\"")); // white telephone & black flag symbol
@@ -1041,7 +1873,7 @@ tcu::TestCaseGroup* createOpSourceExtensionGroup (tcu::TestContext& testCtx)
        cases.push_back(CaseParameter("real_extension",         "GL_ARB_texture_rectangle"));
        cases.push_back(CaseParameter("fake_extension",         "GL_ARB_im_the_ultimate_extension"));
        cases.push_back(CaseParameter("utf8_extension",         "GL_ARB_\xE2\x98\x82\xE2\x98\x85"));
-       cases.push_back(CaseParameter("long_extension",         string(65533, 'e'))); // word count: 65535
+       cases.push_back(CaseParameter("long_extension",         makeLongUTF8String(65533) + "ccc")); // word count: 65535
 
        fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
 
@@ -1221,6 +2053,485 @@ tcu::TestCaseGroup* createOpConstantCompositeGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
+// Creates a floating point number with the given exponent, and significand
+// bits set. It can only create normalized numbers. Only the least significant
+// 24 bits of the significand will be examined. The final bit of the
+// significand will also be ignored. This allows alignment to be written
+// similarly to C99 hex-floats.
+// For example if you wanted to write 0x1.7f34p-12 you would call
+// constructNormalizedFloat(-12, 0x7f3400)
+float constructNormalizedFloat (deInt32 exponent, deUint32 significand)
+{
+       float f = 1.0f;
+
+       for (deInt32 idx = 0; idx < 23; ++idx)
+       {
+               f += ((significand & 0x800000) == 0) ? 0.f : std::ldexp(1.0f, -idx);
+               significand <<= 1;
+       }
+
+       return std::ldexp(f, exponent);
+}
+
+// Compare instruction for the OpQuantizeF16 compute exact case.
+// Returns true if the output is what is expected from the test case.
+bool compareOpQuantizeF16ComputeExactCase (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs)
+{
+       if (outputAllocs.size() != 1)
+               return false;
+
+       // We really just need this for size because we cannot compare Nans.
+       const BufferSp& expectedOutput  = expectedOutputs[0];
+       const float*    outputAsFloat   = static_cast<const float*>(outputAllocs[0]->getHostPtr());;
+
+       if (expectedOutput->getNumBytes() != 4*sizeof(float)) {
+               return false;
+       }
+
+       if (*outputAsFloat != constructNormalizedFloat(8, 0x304000) &&
+               *outputAsFloat != constructNormalizedFloat(8, 0x300000)) {
+               return false;
+       }
+
+       if (*outputAsFloat != -constructNormalizedFloat(-7, 0x600000) &&
+               *outputAsFloat != -constructNormalizedFloat(-7, 0x604000)) {
+               return false;
+       }
+
+       if (*outputAsFloat != constructNormalizedFloat(2, 0x01C000) &&
+               *outputAsFloat != constructNormalizedFloat(2, 0x020000)) {
+               return false;
+       }
+
+       if (*outputAsFloat != constructNormalizedFloat(1, 0xFFC000) &&
+               *outputAsFloat != constructNormalizedFloat(2, 0x000000)) {
+               return false;
+       }
+
+       return true;
+}
+
+// Checks that every output from a test-case is a float NaN.
+bool compareNan (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs)
+{
+       if (outputAllocs.size() != 1)
+               return false;
+
+       // We really just need this for size because we cannot compare Nans.
+       const BufferSp& expectedOutput          = expectedOutputs[0];
+       const float* output_as_float            = static_cast<const float*>(outputAllocs[0]->getHostPtr());;
+
+       for (size_t idx = 0; idx < expectedOutput->getNumBytes() / sizeof(float); ++idx)
+       {
+               if (!isnan(output_as_float[idx]))
+               {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+// Checks that a compute shader can generate a constant composite value of various types, without exercising a computation on it.
+tcu::TestCaseGroup* createOpQuantizeToF16Group (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opquantize", "Tests the OpQuantizeToF16 instruction"));
+
+       const std::string shader (
+               string(s_ShaderPreamble) +
+
+               "OpSource GLSL 430\n"
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%idval     = OpLoad %uvec3 %id\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
+               "%inval     = OpLoad %f32 %inloc\n"
+               "%quant     = OpQuantizeToF16 %f32 %inval\n"
+               "%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "             OpStore %outloc %quant\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n");
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint32          numElements             = 100;
+               vector<float>           infinities;
+               vector<float>           results;
+
+               infinities.reserve(numElements);
+               results.reserve(numElements);
+
+               for (size_t idx = 0; idx < numElements; ++idx)
+               {
+                       switch(idx % 4)
+                       {
+                               case 0:
+                                       infinities.push_back(std::numeric_limits<float>::infinity());
+                                       results.push_back(std::numeric_limits<float>::infinity());
+                                       break;
+                               case 1:
+                                       infinities.push_back(-std::numeric_limits<float>::infinity());
+                                       results.push_back(-std::numeric_limits<float>::infinity());
+                                       break;
+                               case 2:
+                                       infinities.push_back(std::ldexp(1.0f, 16));
+                                       results.push_back(std::numeric_limits<float>::infinity());
+                                       break;
+                               case 3:
+                                       infinities.push_back(std::ldexp(-1.0f, 32));
+                                       results.push_back(-std::numeric_limits<float>::infinity());
+                                       break;
+                       }
+               }
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(infinities)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(results)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "infinities", "Check that infinities propagated and created", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               vector<float>           nans;
+               const deUint32          numElements             = 100;
+
+               nans.reserve(numElements);
+
+               for (size_t idx = 0; idx < numElements; ++idx)
+               {
+                       if (idx % 2 == 0)
+                       {
+                               nans.push_back(std::numeric_limits<float>::quiet_NaN());
+                       }
+                       else
+                       {
+                               nans.push_back(-std::numeric_limits<float>::quiet_NaN());
+                       }
+               }
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(nans)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(nans)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+               spec.verifyIO = &compareNan;
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "propagated_nans", "Check that nans are propagated", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               vector<float>           small;
+               vector<float>           zeros;
+               const deUint32          numElements             = 100;
+
+               small.reserve(numElements);
+               zeros.reserve(numElements);
+
+               for (size_t idx = 0; idx < numElements; ++idx)
+               {
+                       switch(idx % 6)
+                       {
+                               case 0:
+                                       small.push_back(0.f);
+                                       zeros.push_back(0.f);
+                                       break;
+                               case 1:
+                                       small.push_back(-0.f);
+                                       zeros.push_back(-0.f);
+                                       break;
+                               case 2:
+                                       small.push_back(std::ldexp(1.0f, -16));
+                                       zeros.push_back(0.f);
+                                       break;
+                               case 3:
+                                       small.push_back(std::ldexp(-1.0f, -32));
+                                       zeros.push_back(-0.f);
+                                       break;
+                               case 4:
+                                       small.push_back(std::ldexp(1.0f, -127));
+                                       zeros.push_back(0.f);
+                                       break;
+                               case 5:
+                                       small.push_back(-std::ldexp(1.0f, -128));
+                                       zeros.push_back(-0.f);
+                                       break;
+                       }
+               }
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(small)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(zeros)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               vector<float>           exact;
+               const deUint32          numElements             = 200;
+
+               exact.reserve(numElements);
+
+               for (size_t idx = 0; idx < numElements; ++idx)
+                       exact.push_back(static_cast<float>(idx - 100));
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(exact)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(exact)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               vector<float>           inputs;
+               const deUint32          numElements             = 4;
+
+               inputs.push_back(constructNormalizedFloat(8,    0x300300));
+               inputs.push_back(-constructNormalizedFloat(-7,  0x600800));
+               inputs.push_back(constructNormalizedFloat(2,    0x01E000));
+               inputs.push_back(constructNormalizedFloat(1,    0xFFE000));
+
+               spec.verifyIO = &compareOpQuantizeF16ComputeExactCase;
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "rounded", "Check that are rounded when needed", spec));
+       }
+
+       return group.release();
+}
+
+// Performs a bitwise copy of source to the destination type Dest.
+template <typename Dest, typename Src>
+Dest bitwiseCast(Src source)
+{
+  Dest dest;
+  DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
+  deMemcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+tcu::TestCaseGroup* createSpecConstantOpQuantizeToF16Group (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opspecconstantop_opquantize", "Tests the OpQuantizeToF16 opcode for the OpSpecConstantOp instruction"));
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+
+       const std::string shader (
+               string(s_ShaderPreamble) +
+
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               "OpDecorate %sc_0  SpecId 0\n"
+               "OpDecorate %sc_1  SpecId 1\n"
+               "OpDecorate %sc_2  SpecId 2\n"
+               "OpDecorate %sc_3  SpecId 3\n"
+               "OpDecorate %sc_4  SpecId 4\n"
+               "OpDecorate %sc_5  SpecId 5\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+               "%c_u32_6   = OpConstant %u32 6\n"
+
+               "%sc_0      = OpSpecConstant %f32 0.\n"
+               "%sc_1      = OpSpecConstant %f32 0.\n"
+               "%sc_2      = OpSpecConstant %f32 0.\n"
+               "%sc_3      = OpSpecConstant %f32 0.\n"
+               "%sc_4      = OpSpecConstant %f32 0.\n"
+               "%sc_5      = OpSpecConstant %f32 0.\n"
+
+               "%sc_0_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_0\n"
+               "%sc_1_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_1\n"
+               "%sc_2_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_2\n"
+               "%sc_3_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_3\n"
+               "%sc_4_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_4\n"
+               "%sc_5_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_5\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+               "%idval     = OpLoad %uvec3 %id\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "%selector  = OpUMod %u32 %x %c_u32_6\n"
+               "            OpSelectionMerge %exit None\n"
+               "            OpSwitch %selector %exit 0 %case0 1 %case1 2 %case2 3 %case3 4 %case4 5 %case5\n"
+
+               "%case0     = OpLabel\n"
+               "             OpStore %outloc %sc_0_quant\n"
+               "             OpBranch %exit\n"
+
+               "%case1     = OpLabel\n"
+               "             OpStore %outloc %sc_1_quant\n"
+               "             OpBranch %exit\n"
+
+               "%case2     = OpLabel\n"
+               "             OpStore %outloc %sc_2_quant\n"
+               "             OpBranch %exit\n"
+
+               "%case3     = OpLabel\n"
+               "             OpStore %outloc %sc_3_quant\n"
+               "             OpBranch %exit\n"
+
+               "%case4     = OpLabel\n"
+               "             OpStore %outloc %sc_4_quant\n"
+               "             OpBranch %exit\n"
+
+               "%case5     = OpLabel\n"
+               "             OpStore %outloc %sc_5_quant\n"
+               "             OpBranch %exit\n"
+
+               "%exit      = OpLabel\n"
+               "             OpReturn\n"
+
+               "             OpFunctionEnd\n");
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint8           numCases        = 4;
+               vector<float>           inputs          (numCases, 0.f);
+               vector<float>           outputs;
+
+               spec.numWorkGroups = IVec3(numCases, 1, 1);
+
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::numeric_limits<float>::infinity()));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(-std::numeric_limits<float>::infinity()));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, 16)));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, 32)));
+
+               outputs.push_back(std::numeric_limits<float>::infinity());
+               outputs.push_back(-std::numeric_limits<float>::infinity());
+               outputs.push_back(std::numeric_limits<float>::infinity());
+               outputs.push_back(-std::numeric_limits<float>::infinity());
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "infinities", "Check that infinities propagated and created", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint8           numCases        = 2;
+               vector<float>           inputs          (numCases, 0.f);
+               vector<float>           outputs;
+
+               spec.numWorkGroups      = IVec3(numCases, 1, 1);
+               spec.verifyIO           = &compareNan;
+
+               outputs.push_back(std::numeric_limits<float>::quiet_NaN());
+               outputs.push_back(-std::numeric_limits<float>::quiet_NaN());
+
+               for (deUint8 idx = 0; idx < numCases; ++idx)
+                       spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "propagated_nans", "Check that nans are propagated", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint8           numCases        = 6;
+               vector<float>           inputs          (numCases, 0.f);
+               vector<float>           outputs;
+
+               spec.numWorkGroups      = IVec3(numCases, 1, 1);
+
+               spec.specConstants.push_back(bitwiseCast<deUint32>(0.f));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(-0.f));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -16)));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, -32)));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -127)));
+               spec.specConstants.push_back(bitwiseCast<deUint32>(-std::ldexp(1.0f, -128)));
+
+               outputs.push_back(0.f);
+               outputs.push_back(-0.f);
+               outputs.push_back(0.f);
+               outputs.push_back(-0.f);
+               outputs.push_back(0.f);
+               outputs.push_back(-0.f);
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint8           numCases        = 6;
+               vector<float>           inputs          (numCases, 0.f);
+               vector<float>           outputs;
+
+               spec.numWorkGroups      = IVec3(numCases, 1, 1);
+
+               for (deUint8 idx = 0; idx < 6; ++idx)
+               {
+                       const float f = static_cast<float>(idx * 10 - 30) / 4.f;
+                       spec.specConstants.push_back(bitwiseCast<deUint32>(f));
+                       outputs.push_back(f);
+               }
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
+       }
+
+       {
+               ComputeShaderSpec       spec;
+               const deUint8           numCases        = 4;
+               vector<float>           inputs          (numCases, 0.f);
+               vector<float>           outputs;
+
+               spec.numWorkGroups      = IVec3(numCases, 1, 1);
+               spec.verifyIO           = &compareOpQuantizeF16ComputeExactCase;
+
+               outputs.push_back(constructNormalizedFloat(8, 0x300300));
+               outputs.push_back(-constructNormalizedFloat(-7, 0x600800));
+               outputs.push_back(constructNormalizedFloat(2, 0x01E000));
+               outputs.push_back(constructNormalizedFloat(1, 0xFFE000));
+
+               for (deUint8 idx = 0; idx < numCases; ++idx)
+                       spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
+
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
+
+               group->addChild(new SpvAsmComputeShaderCase(
+                       testCtx, "rounded", "Check that are rounded when needed", spec));
+       }
+
+       return group.release();
+}
+
 // Checks that constant null/composite values can be used in computation.
 tcu::TestCaseGroup* createOpConstantUsageGroup (tcu::TestContext& testCtx)
 {
@@ -1595,15 +2906,14 @@ tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
-// Checks that we can get undefined values for various types, without exercising a computation with it.
-tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
+tcu::TestCaseGroup* createMemoryAccessGroup (tcu::TestContext& testCtx)
 {
-       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "memory_access", "Tests memory access cases"));
        vector<CaseParameter>                   cases;
        de::Random                                              rnd                             (deStringHash(group->getName()));
        const int                                               numElements             = 100;
-       vector<float>                                   positiveFloats  (numElements, 0);
-       vector<float>                                   negativeFloats  (numElements, 0);
+       vector<float>                                   inputFloats             (numElements, 0);
+       vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
                string(s_ShaderPreamble) +
 
@@ -1615,15 +2925,86 @@ tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
 
                + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
 
-               "${TYPE}\n"
+               "%f32ptr_f  = OpTypePointer Function %f32\n"
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
+               "%four      = OpConstant %i32 4\n"
 
                "%main      = OpFunction %void None %voidf\n"
                "%label     = OpLabel\n"
+               "%copy      = OpVariable %f32ptr_f Function\n"
+               "%idval     = OpLoad %uvec3 %id ${ACCESS}\n"
+               "%x         = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc     = OpAccessChain %f32ptr %indata  %zero %x\n"
+               "%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
+               "             OpCopyMemory %copy %inloc ${ACCESS}\n"
+               "%val1      = OpLoad %f32 %copy\n"
+               "%val2      = OpLoad %f32 %inloc\n"
+               "%add       = OpFAdd %f32 %val1 %val2\n"
+               "             OpStore %outloc %add ${ACCESS}\n"
+               "             OpReturn\n"
+               "             OpFunctionEnd\n");
 
-               "%undef     = OpUndef %type\n"
+       cases.push_back(CaseParameter("null",                                   ""));
+       cases.push_back(CaseParameter("none",                                   "None"));
+       cases.push_back(CaseParameter("volatile",                               "Volatile"));
+       cases.push_back(CaseParameter("aligned",                                "Aligned 4"));
+       cases.push_back(CaseParameter("nontemporal",                    "Nontemporal"));
+       cases.push_back(CaseParameter("aligned_nontemporal",    "Aligned|Nontemporal 4"));
+       cases.push_back(CaseParameter("aligned_volatile",               "Volatile|Aligned 4"));
+
+       fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
+
+       for (size_t ndx = 0; ndx < numElements; ++ndx)
+               outputFloats[ndx] = inputFloats[ndx] + inputFloats[ndx];
+
+       for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+       {
+               map<string, string>             specializations;
+               ComputeShaderSpec               spec;
+
+               specializations["ACCESS"] = cases[caseNdx].param;
+               spec.assembly = shaderTemplate.specialize(specializations);
+               spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
+               spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+               group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
+       }
+
+       return group.release();
+}
+
+// Checks that we can get undefined values for various types, without exercising a computation with it.
+tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
+       vector<CaseParameter>                   cases;
+       de::Random                                              rnd                             (deStringHash(group->getName()));
+       const int                                               numElements             = 100;
+       vector<float>                                   positiveFloats  (numElements, 0);
+       vector<float>                                   negativeFloats  (numElements, 0);
+       const StringTemplate                    shaderTemplate  (
+               string(s_ShaderPreamble) +
+
+               "OpSource GLSL 430\n"
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+
+               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+
+               "${TYPE}\n"
+
+               "%id        = OpVariable %uvec3ptr Input\n"
+               "%zero      = OpConstant %i32 0\n"
+
+               "%main      = OpFunction %void None %voidf\n"
+               "%label     = OpLabel\n"
+
+               "%undef     = OpUndef %type\n"
 
                "%idval     = OpLoad %uvec3 %id\n"
                "%x         = OpCompositeExtract %u32 %idval 0\n"
@@ -1666,8 +3047,8 @@ tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
 
                specializations["TYPE"] = cases[caseNdx].param;
                spec.assembly = shaderTemplate.specialize(specializations);
-       spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
-       spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
+               spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
+               spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
                spec.numWorkGroups = IVec3(numElements, 1, 1);
 
                group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
@@ -1675,9 +3056,9 @@ tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
 
                return group.release();
 }
-
 typedef std::pair<std::string, VkShaderStageFlagBits>  EntryToStage;
 typedef map<string, vector<EntryToStage> >                             ModuleMap;
+typedef map<VkShaderStageFlagBits, vector<deInt32> >   StageToSpecConstantMap;
 
 // Context for a specific test instantiation. For example, an instantiation
 // may test colors yellow/magenta/cyan/mauve in a tesselation shader
@@ -1690,9 +3071,13 @@ struct InstanceContext
        RGBA                                    outputColors[4];
        // Concrete SPIR-V code to test via boilerplate specialization.
        map<string, string>             testCodeFragments;
+       StageToSpecConstantMap  specConstants;
 
-       InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_)
-               : testCodeFragments             (testCodeFragments_)
+       bool                                    hasTessellation;
+       InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_, const StageToSpecConstantMap& specConstants_)
+               : testCodeFragments     (testCodeFragments_)
+               , specConstants         (specConstants_)
+               , hasTessellation       (false)
        {
                inputColors[0]          = inputs[0];
                inputColors[1]          = inputs[1];
@@ -1708,6 +3093,8 @@ struct InstanceContext
        InstanceContext (const InstanceContext& other)
                : moduleMap                     (other.moduleMap)
                , testCodeFragments     (other.testCodeFragments)
+               , specConstants         (other.specConstants)
+               , hasTessellation       (other.hasTessellation)
        {
                inputColors[0]          = other.inputColors[0];
                inputColors[1]          = other.inputColors[1];
@@ -1725,15 +3112,15 @@ struct InstanceContext
 struct ShaderElement
 {
        // The module that contains this shader entrypoint.
-       const char*                             moduleName;
+       string                                  moduleName;
 
        // The name of the entrypoint.
-       const char*                             entryName;
+       string                                  entryName;
 
        // Which shader stage this entry point represents.
        VkShaderStageFlagBits   stage;
 
-       ShaderElement (const char* moduleName_, const char* entryPoint_, VkShaderStageFlagBits shaderStage_)
+       ShaderElement (const string& moduleName_, const string& entryPoint_, VkShaderStageFlagBits shaderStage_)
                : moduleName(moduleName_)
                , entryName(entryPoint_)
                , stage(shaderStage_)
@@ -1745,24 +3132,51 @@ void getDefaultColors (RGBA (&colors)[4])
 {
        colors[0] = RGBA::white();
        colors[1] = RGBA::red();
-       colors[2] = RGBA::blue();
-       colors[3] = RGBA::green();
+       colors[2] = RGBA::green();
+       colors[3] = RGBA::blue();
+}
+
+void getHalfColorsFullAlpha (RGBA (&colors)[4])
+{
+       colors[0] = RGBA(127, 127, 127, 255);
+       colors[1] = RGBA(127, 0,   0,   255);
+       colors[2] = RGBA(0,       127, 0,       255);
+       colors[3] = RGBA(0,       0,   127, 255);
+}
+
+void getInvertedDefaultColors (RGBA (&colors)[4])
+{
+       colors[0] = RGBA(0,             0,              0,              255);
+       colors[1] = RGBA(0,             255,    255,    255);
+       colors[2] = RGBA(255,   0,              255,    255);
+       colors[3] = RGBA(255,   255,    0,              255);
 }
 
 // Turns a statically sized array of ShaderElements into an instance-context
 // by setting up the mapping of modules to their contained shaders and stages.
 // The inputs and expected outputs are given by inputColors and outputColors
 template<size_t N>
-InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
+InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const StageToSpecConstantMap& specConstants)
 {
-       InstanceContext ctx (inputColors, outputColors, testCodeFragments);
+       InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants);
        for (size_t i = 0; i < N; ++i)
        {
                ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
+               if (elements[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
+                       elements[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+               {
+                       ctx.hasTessellation = true;
+               }
        }
        return ctx;
 }
 
+template<size_t N>
+inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
+{
+       return createInstanceContext(elements, inputColors, outputColors, testCodeFragments, StageToSpecConstantMap());
+}
+
 // The same as createInstanceContext above, but with default colors.
 template<size_t N>
 InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const map<string, string>& testCodeFragments)
@@ -1778,9 +3192,7 @@ void createPipelineShaderStages (const DeviceInterface& vk, const VkDevice vkDev
        for (ModuleMap::const_iterator moduleNdx = instance.moduleMap.begin(); moduleNdx != instance.moduleMap.end(); ++moduleNdx)
        {
                const ModuleHandleSp mod(new Unique<VkShaderModule>(createShaderModule(vk, vkDevice, context.getBinaryCollection().get(moduleNdx->first), 0)));
-
                modules.push_back(ModuleHandleSp(mod));
-
                for (vector<EntryToStage>::const_iterator shaderNdx = moduleNdx->second.begin(); shaderNdx != moduleNdx->second.end(); ++shaderNdx)
                {
                        const EntryToStage&                                             stage                   = *shaderNdx;
@@ -1794,56 +3206,68 @@ void createPipelineShaderStages (const DeviceInterface& vk, const VkDevice vkDev
                                stage.first.c_str(),                                                                    //      const char*                             pName;
                                (const VkSpecializationInfo*)DE_NULL,
                        };
-
                        createInfos.push_back(shaderParam);
                }
        }
 }
 
-#define SPIRV_ASSEMBLY_TYPES                                                                                           \
-       "%void = OpTypeVoid\n"                                                                                                  \
-       "%bool = OpTypeBool\n"                                                                                                  \
-                                                                                                                                                       \
-       "%i32 = OpTypeInt 32 1\n"                                                                                               \
-       "%u32 = OpTypeInt 32 0\n"                                                                                               \
-                                                                                                                                                       \
-       "%f32 = OpTypeFloat 32\n"                                                                                               \
-       "%v3f32 = OpTypeVector %f32 3\n"                                                                                \
-       "%v4f32 = OpTypeVector %f32 4\n"                                                                                \
-                                                                                                                                                       \
-       "%v4f32_function = OpTypeFunction %v4f32 %v4f32\n"                                              \
-       "%fun = OpTypeFunction %void\n"                                                                                 \
-                                                                                                                                                       \
-       "%ip_f32 = OpTypePointer Input %f32\n"                                                                  \
-       "%ip_i32 = OpTypePointer Input %i32\n"                                                                  \
-       "%ip_v3f32 = OpTypePointer Input %v3f32\n"                                                              \
-       "%ip_v4f32 = OpTypePointer Input %v4f32\n"                                                              \
-                                                                                                                                                       \
-       "%op_f32 = OpTypePointer Output %f32\n"                                                                 \
-       "%op_v4f32 = OpTypePointer Output %v4f32\n"
-
-#define SPIRV_ASSEMBLY_CONSTANTS                                                                                       \
-       "%c_f32_1 = OpConstant %f32 1\n"                                                                                \
-       "%c_i32_0 = OpConstant %i32 0\n"                                                                                \
-       "%c_i32_1 = OpConstant %i32 1\n"                                                                                \
-       "%c_i32_2 = OpConstant %i32 2\n"                                                                                \
-       "%c_u32_0 = OpConstant %u32 0\n"                                                                                \
-       "%c_u32_1 = OpConstant %u32 1\n"                                                                                \
-       "%c_u32_2 = OpConstant %u32 2\n"                                                                                \
-       "%c_u32_3 = OpConstant %u32 3\n"                                                                                \
-       "%c_u32_32 = OpConstant %u32 32\n"                                                                              \
-       "%c_u32_4 = OpConstant %u32 4\n"
-
-#define SPIRV_ASSEMBLY_ARRAYS                                                                                          \
-       "%a1f32 = OpTypeArray %f32 %c_u32_1\n"                                                                  \
-       "%a2f32 = OpTypeArray %f32 %c_u32_2\n"                                                                  \
-       "%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n"                                                              \
-       "%a4f32 = OpTypeArray %f32 %c_u32_4\n"                                                                  \
-       "%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n"                                                    \
-       "%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n"                                                  \
-       "%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n"                                                \
-       "%op_a2f32 = OpTypePointer Output %a2f32\n"                                                             \
-       "%op_a3v4f32 = OpTypePointer Output %a3v4f32\n"                                                 \
+#define SPIRV_ASSEMBLY_TYPES                                                                                                                                   \
+       "%void = OpTypeVoid\n"                                                                                                                                          \
+       "%bool = OpTypeBool\n"                                                                                                                                          \
+                                                                                                                                                                                               \
+       "%i32 = OpTypeInt 32 1\n"                                                                                                                                       \
+       "%u32 = OpTypeInt 32 0\n"                                                                                                                                       \
+                                                                                                                                                                                               \
+       "%f32 = OpTypeFloat 32\n"                                                                                                                                       \
+       "%v3f32 = OpTypeVector %f32 3\n"                                                                                                                        \
+       "%v4f32 = OpTypeVector %f32 4\n"                                                                                                                        \
+                                                                                                                                                                                               \
+       "%v4f32_function = OpTypeFunction %v4f32 %v4f32\n"                                                                                      \
+       "%fun = OpTypeFunction %void\n"                                                                                                                         \
+                                                                                                                                                                                               \
+       "%ip_f32 = OpTypePointer Input %f32\n"                                                                                                          \
+       "%ip_i32 = OpTypePointer Input %i32\n"                                                                                                          \
+       "%ip_v3f32 = OpTypePointer Input %v3f32\n"                                                                                                      \
+       "%ip_v4f32 = OpTypePointer Input %v4f32\n"                                                                                                      \
+                                                                                                                                                                                               \
+       "%op_f32 = OpTypePointer Output %f32\n"                                                                                                         \
+       "%op_v4f32 = OpTypePointer Output %v4f32\n"                                                                                                     \
+                                                                                                                                                                                               \
+       "%fp_f32   = OpTypePointer Function %f32\n"                                                                                                     \
+       "%fp_i32   = OpTypePointer Function %i32\n"                                                                                                     \
+       "%fp_v4f32 = OpTypePointer Function %v4f32\n"
+
+#define SPIRV_ASSEMBLY_CONSTANTS                                                                                                                               \
+       "%c_f32_1 = OpConstant %f32 1.0\n"                                                                                                                      \
+       "%c_f32_0 = OpConstant %f32 0.0\n"                                                                                                                      \
+       "%c_f32_0_5 = OpConstant %f32 0.5\n"                                                                                                            \
+       "%c_f32_n1  = OpConstant %f32 -1.\n"                                                                                                            \
+       "%c_i32_0 = OpConstant %i32 0\n"                                                                                                                        \
+       "%c_i32_1 = OpConstant %i32 1\n"                                                                                                                        \
+       "%c_i32_2 = OpConstant %i32 2\n"                                                                                                                        \
+       "%c_i32_3 = OpConstant %i32 3\n"                                                                                                                        \
+       "%c_i32_4 = OpConstant %i32 4\n"                                                                                                                        \
+       "%c_u32_0 = OpConstant %u32 0\n"                                                                                                                        \
+       "%c_u32_1 = OpConstant %u32 1\n"                                                                                                                        \
+       "%c_u32_2 = OpConstant %u32 2\n"                                                                                                                        \
+       "%c_u32_3 = OpConstant %u32 3\n"                                                                                                                        \
+       "%c_u32_32 = OpConstant %u32 32\n"                                                                                                                      \
+       "%c_u32_4 = OpConstant %u32 4\n"                                                                                                                        \
+       "%c_u32_31_bits = OpConstant %u32 0x7FFFFFFF\n"                                                                                         \
+       "%c_v4f32_1_1_1_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"           \
+       "%c_v4f32_1_0_0_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_1\n"           \
+       "%c_v4f32_0_5_0_5_0_5_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5\n"
+
+#define SPIRV_ASSEMBLY_ARRAYS                                                                                                                                  \
+       "%a1f32 = OpTypeArray %f32 %c_u32_1\n"                                                                                                          \
+       "%a2f32 = OpTypeArray %f32 %c_u32_2\n"                                                                                                          \
+       "%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n"                                                                                                      \
+       "%a4f32 = OpTypeArray %f32 %c_u32_4\n"                                                                                                          \
+       "%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n"                                                                                            \
+       "%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n"                                                                                          \
+       "%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n"                                                                                        \
+       "%op_a2f32 = OpTypePointer Output %a2f32\n"                                                                                                     \
+       "%op_a3v4f32 = OpTypePointer Output %a3v4f32\n"                                                                                         \
        "%op_a4f32 = OpTypePointer Output %a4f32\n"
 
 // Creates vertex-shader assembly by specializing a boilerplate StringTemplate
@@ -1863,7 +3287,7 @@ string makeVertexShaderAssembly(const map<string, string>& fragments)
        static const char vertexShaderBoilerplate[] =
                "OpCapability Shader\n"
                "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint Vertex %4 \"main\" %BP_Position %BP_vtxColor %BP_color "
+               "OpEntryPoint Vertex %main \"main\" %BP_Position %BP_vtxColor %BP_color "
                "%BP_vtxPosition %BP_vertex_id %BP_instance_id\n"
                "${debug:opt}\n"
                "OpName %main \"main\"\n"
@@ -1871,8 +3295,8 @@ string makeVertexShaderAssembly(const map<string, string>& fragments)
                "OpName %BP_Position \"position\"\n"
                "OpName %BP_vtxColor \"vtxColor\"\n"
                "OpName %BP_color \"color\"\n"
-               "OpName %vertex_id \"gl_VertexID\"\n"
-               "OpName %instance_id \"gl_InstanceID\"\n"
+               "OpName %BP_vertex_id \"gl_VertexID\"\n"
+               "OpName %BP_instance_id \"gl_InstanceID\"\n"
                "OpName %test_code \"testfun(vf4;\"\n"
                "OpDecorate %BP_vtxPosition Location 2\n"
                "OpDecorate %BP_Position Location 0\n"
@@ -1880,6 +3304,7 @@ string makeVertexShaderAssembly(const map<string, string>& fragments)
                "OpDecorate %BP_color Location 1\n"
                "OpDecorate %BP_vertex_id BuiltIn VertexId\n"
                "OpDecorate %BP_instance_id BuiltIn InstanceId\n"
+               "${decoration:opt}\n"
                SPIRV_ASSEMBLY_TYPES
                SPIRV_ASSEMBLY_CONSTANTS
                SPIRV_ASSEMBLY_ARRAYS
@@ -1889,6 +3314,7 @@ string makeVertexShaderAssembly(const map<string, string>& fragments)
                "%BP_color = OpVariable %ip_v4f32 Input\n"
                "%BP_vertex_id = OpVariable %ip_i32 Input\n"
                "%BP_instance_id = OpVariable %ip_i32 Input\n"
+               "${pre_main:opt}\n"
                "%main = OpFunction %void None %fun\n"
                "%BP_label = OpLabel\n"
                "%BP_tmp_position = OpLoad %v4f32 %BP_Position\n"
@@ -1952,6 +3378,7 @@ string makeTessControlShaderAssembly (const map<string, string>& fragments)
                "OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
                "OpDecorate %BP_gl_TessLevelInner Patch\n"
                "OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
+               "${decoration:opt}\n"
                SPIRV_ASSEMBLY_TYPES
                SPIRV_ASSEMBLY_CONSTANTS
                SPIRV_ASSEMBLY_ARRAYS
@@ -1962,6 +3389,7 @@ string makeTessControlShaderAssembly (const map<string, string>& fragments)
                "%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
                "%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
                "%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+               "${pre_main:opt}\n"
 
                "%BP_main = OpFunction %void None %fun\n"
                "%BP_label = OpLabel\n"
@@ -2058,6 +3486,7 @@ string makeTessEvalShaderAssembly(const map<string, string>& fragments)
                "OpDecorate %BP_in_position Location 2\n"
                "OpDecorate %BP_out_color Location 1\n"
                "OpDecorate %BP_in_color Location 1\n"
+               "${decoration:opt}\n"
                SPIRV_ASSEMBLY_TYPES
                SPIRV_ASSEMBLY_CONSTANTS
                SPIRV_ASSEMBLY_ARRAYS
@@ -2068,6 +3497,8 @@ string makeTessEvalShaderAssembly(const map<string, string>& fragments)
                "%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
                "%BP_out_color = OpVariable %op_v4f32 Output\n"
                "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
+               "${pre_main:opt}\n"
+
                "%BP_main = OpFunction %void None %fun\n"
                "%BP_label = OpLabel\n"
                "%BP_tc_0_ptr = OpAccessChain %ip_f32 %BP_gl_tessCoord %c_u32_0\n"
@@ -2175,6 +3606,7 @@ string makeGeometryShaderAssembly(const map<string, string>& fragments)
                "OpDecorate %BP_out_color Location 1\n"
                "OpDecorate %BP_out_color Stream 0\n"
                "OpDecorate %BP_in_color Location 1\n"
+               "${decoration:opt}\n"
                SPIRV_ASSEMBLY_TYPES
                SPIRV_ASSEMBLY_CONSTANTS
                SPIRV_ASSEMBLY_ARRAYS
@@ -2186,6 +3618,7 @@ string makeGeometryShaderAssembly(const map<string, string>& fragments)
                "%BP_out_color = OpVariable %op_v4f32 Output\n"
                "%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
                "%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
+               "${pre_main:opt}\n"
 
                "%BP_main = OpFunction %void None %fun\n"
                "%BP_label = OpLabel\n"
@@ -2209,6 +3642,7 @@ string makeGeometryShaderAssembly(const map<string, string>& fragments)
                "%BP_transformed_in_color_1 = OpFunctionCall %v4f32 %test_code %BP_in_color_1\n"
                "%BP_transformed_in_color_2 = OpFunctionCall %v4f32 %test_code %BP_in_color_2\n"
 
+
                "OpStore %BP_out_gl_position %BP_in_position_0\n"
                "OpStore %BP_out_color %BP_transformed_in_color_0\n"
                "OpEmitVertex\n"
@@ -2256,11 +3690,13 @@ string makeFragmentShaderAssembly(const map<string, string>& fragments)
                "OpName %test_code \"testfun(vf4;\"\n"
                "OpDecorate %BP_fragColor Location 0\n"
                "OpDecorate %BP_vtxColor Location 1\n"
+               "${decoration:opt}\n"
                SPIRV_ASSEMBLY_TYPES
                SPIRV_ASSEMBLY_CONSTANTS
                SPIRV_ASSEMBLY_ARRAYS
                "%BP_fragColor = OpVariable %op_v4f32 Output\n"
                "%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
+               "${pre_main:opt}\n"
                "%BP_main = OpFunction %void None %fun\n"
                "%BP_label_main = OpLabel\n"
                "%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
@@ -2288,7 +3724,8 @@ map<string, string> passthruFragments(void)
 
 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
 // Vertex shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context)
+{
        map<string, string> passthru = passthruFragments();
        dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
        dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
@@ -2300,7 +3737,8 @@ void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext conte
 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
 // Tessellation control shader gets custom code from context, the rest are
 // pass-through.
-void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context)
+{
        map<string, string> passthru = passthruFragments();
        dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
        dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
@@ -2312,7 +3750,8 @@ void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext
 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
 // Tessellation evaluation shader gets custom code from context, the rest are
 // pass-through.
-void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context)
+{
        map<string, string> passthru = passthruFragments();
        dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
        dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
@@ -2323,7 +3762,8 @@ void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext con
 
 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
 // Geometry shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context)
+{
        map<string, string> passthru = passthruFragments();
        dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
        dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
@@ -2334,7 +3774,8 @@ void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext con
 
 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
 // Fragment shader gets custom code from context, the rest are pass-through.
-void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context) {
+void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context)
+{
        map<string, string> passthru = passthruFragments();
        dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
        dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
@@ -2343,6 +3784,678 @@ void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext con
        dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(context.testCodeFragments);
 }
 
+void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
+{
+       // \todo [2015-12-07 awoloszyn] Make tessellation / geometry conditional
+       // \todo [2015-12-07 awoloszyn] Remove OpName and OpMemeberName at some point
+       dst.spirvAsmSources.add("module") <<
+               "OpCapability Shader\n"
+               "OpCapability Geometry\n"
+               "OpCapability Tessellation\n"
+               "OpMemoryModel Logical GLSL450\n"
+
+               "OpEntryPoint Vertex %vert_main \"main\" %vert_Position %vert_vtxColor %vert_color %vert_vtxPosition %vert_vertex_id %vert_instance_id\n"
+               "OpEntryPoint Geometry %geom_main \"main\" %out_gl_position %gl_in %out_color %in_color\n"
+               "OpEntryPoint TessellationControl %tessc_main \"main\" %tessc_out_color %tessc_gl_InvocationID %tessc_in_color %tessc_out_position %tessc_in_position %tessc_gl_TessLevelOuter %tessc_gl_TessLevelInner\n"
+               "OpEntryPoint TessellationEvaluation %tesse_main \"main\" %tesse_stream %tesse_gl_tessCoord %tesse_in_position %tesse_out_color %tesse_in_color \n"
+               "OpEntryPoint Fragment %frag_main \"main\" %frag_vtxColor %frag_fragColor\n"
+
+               "OpExecutionMode %geom_main Triangles\n"
+               "OpExecutionMode %geom_main Invocations 0\n"
+               "OpExecutionMode %geom_main OutputTriangleStrip\n"
+               "OpExecutionMode %geom_main OutputVertices 3\n"
+
+               "OpExecutionMode %tessc_main OutputVertices 3\n"
+
+               "OpExecutionMode %tesse_main Triangles\n"
+
+               "OpExecutionMode %frag_main OriginUpperLeft\n"
+
+               "; Vertex decorations\n"
+               "OpName %vert_main \"main\"\n"
+               "OpName %vert_vtxPosition \"vtxPosition\"\n"
+               "OpName %vert_Position \"position\"\n"
+               "OpName %vert_vtxColor \"vtxColor\"\n"
+               "OpName %vert_color \"color\"\n"
+               "OpName %vert_vertex_id \"gl_VertexID\"\n"
+               "OpName %vert_instance_id \"gl_InstanceID\"\n"
+               "OpDecorate %vert_vtxPosition Location 2\n"
+               "OpDecorate %vert_Position Location 0\n"
+               "OpDecorate %vert_vtxColor Location 1\n"
+               "OpDecorate %vert_color Location 1\n"
+               "OpDecorate %vert_vertex_id BuiltIn VertexId\n"
+               "OpDecorate %vert_instance_id BuiltIn InstanceId\n"
+
+               "; Geometry decorations\n"
+               "OpName %geom_main \"main\"\n"
+               "OpName %per_vertex_in \"gl_PerVertex\"\n"
+               "OpMemberName %per_vertex_in 0 \"gl_Position\"\n"
+               "OpMemberName %per_vertex_in 1 \"gl_PointSize\"\n"
+               "OpMemberName %per_vertex_in 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %per_vertex_in 3 \"gl_CullDistance\"\n"
+               "OpName %gl_in \"gl_in\"\n"
+               "OpName %out_color \"out_color\"\n"
+               "OpName %in_color \"in_color\"\n"
+               "OpDecorate %out_gl_position BuiltIn Position\n"
+               "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
+               "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
+               "OpDecorate %per_vertex_in Block\n"
+               "OpDecorate %out_color Location 1\n"
+               "OpDecorate %out_color Stream 0\n"
+               "OpDecorate %in_color Location 1\n"
+
+               "; Tessellation Control decorations\n"
+               "OpName %tessc_main \"main\"\n"
+               "OpName %tessc_out_color \"out_color\"\n"
+               "OpName %tessc_gl_InvocationID \"gl_InvocationID\"\n"
+               "OpName %tessc_in_color \"in_color\"\n"
+               "OpName %tessc_out_position \"out_position\"\n"
+               "OpName %tessc_in_position \"in_position\"\n"
+               "OpName %tessc_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
+               "OpName %tessc_gl_TessLevelInner \"gl_TessLevelInner\"\n"
+               "OpDecorate %tessc_out_color Location 1\n"
+               "OpDecorate %tessc_gl_InvocationID BuiltIn InvocationId\n"
+               "OpDecorate %tessc_in_color Location 1\n"
+               "OpDecorate %tessc_out_position Location 2\n"
+               "OpDecorate %tessc_in_position Location 2\n"
+               "OpDecorate %tessc_gl_TessLevelOuter Patch\n"
+               "OpDecorate %tessc_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
+               "OpDecorate %tessc_gl_TessLevelInner Patch\n"
+               "OpDecorate %tessc_gl_TessLevelInner BuiltIn TessLevelInner\n"
+
+               "; Tessellation Evaluation decorations\n"
+               "OpName %tesse_main \"main\"\n"
+               "OpName %tesse_per_vertex_out \"gl_PerVertex\"\n"
+               "OpMemberName %tesse_per_vertex_out 0 \"gl_Position\"\n"
+               "OpMemberName %tesse_per_vertex_out 1 \"gl_PointSize\"\n"
+               "OpMemberName %tesse_per_vertex_out 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %tesse_per_vertex_out 3 \"gl_CullDistance\"\n"
+               "OpName %tesse_stream \"\"\n"
+               "OpName %tesse_gl_tessCoord \"gl_TessCoord\"\n"
+               "OpName %tesse_in_position \"in_position\"\n"
+               "OpName %tesse_out_color \"out_color\"\n"
+               "OpName %tesse_in_color \"in_color\"\n"
+               "OpMemberDecorate %tesse_per_vertex_out 0 BuiltIn Position\n"
+               "OpMemberDecorate %tesse_per_vertex_out 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %tesse_per_vertex_out 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %tesse_per_vertex_out 3 BuiltIn CullDistance\n"
+               "OpDecorate %tesse_per_vertex_out Block\n"
+               "OpDecorate %tesse_gl_tessCoord BuiltIn TessCoord\n"
+               "OpDecorate %tesse_in_position Location 2\n"
+               "OpDecorate %tesse_out_color Location 1\n"
+               "OpDecorate %tesse_in_color Location 1\n"
+
+               "; Fragment decorations\n"
+               "OpName %frag_main \"main\"\n"
+               "OpName %frag_fragColor \"fragColor\"\n"
+               "OpName %frag_vtxColor \"vtxColor\"\n"
+               "OpDecorate %frag_fragColor Location 0\n"
+               "OpDecorate %frag_vtxColor Location 1\n"
+
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+
+               "; Vertex Variables\n"
+               "%vert_vtxPosition = OpVariable %op_v4f32 Output\n"
+               "%vert_Position = OpVariable %ip_v4f32 Input\n"
+               "%vert_vtxColor = OpVariable %op_v4f32 Output\n"
+               "%vert_color = OpVariable %ip_v4f32 Input\n"
+               "%vert_vertex_id = OpVariable %ip_i32 Input\n"
+               "%vert_instance_id = OpVariable %ip_i32 Input\n"
+
+               "; Geometry Variables\n"
+               "%geom_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%geom_a3_per_vertex_in = OpTypeArray %geom_per_vertex_in %c_u32_3\n"
+               "%geom_ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
+               "%geom_gl_in = OpVariable %geom_ip_a3_per_vertex_in Input\n"
+               "%geom_out_color = OpVariable %op_v4f32 Output\n"
+               "%geom_in_color = OpVariable %ip_a3v4f32 Input\n"
+               "%geom_out_gl_position = OpVariable %op_v4f32 Output\n"
+
+               "; Tessellation Control Variables\n"
+               "%tessc_out_color = OpVariable %op_a3v4f32 Output\n"
+               "%tessc_gl_InvocationID = OpVariable %ip_i32 Input\n"
+               "%tessc_in_color = OpVariable %ip_a32v4f32 Input\n"
+               "%tessc_out_position = OpVariable %op_a3v4f32 Output\n"
+               "%tessc_in_position = OpVariable %ip_a32v4f32 Input\n"
+               "%tessc_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
+               "%tessc_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+
+               "; Tessellation Evaluation Decorations\n"
+               "%tesse_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%tesse_op_per_vertex_out = OpTypePointer Output %tesse_per_vertex_out\n"
+               "%tesse_stream = OpVariable %tesse_op_per_vertex_out Output\n"
+               "%tesse_gl_tessCoord = OpVariable %ip_v3f32 Input\n"
+               "%tesse_in_position = OpVariable %ip_a32v4f32 Input\n"
+               "%tesse_out_color = OpVariable %op_v4f32 Output\n"
+               "%tesse_in_color = OpVariable %ip_a32v4f32 Input\n"
+
+               "; Fragment Variables\n"
+               "%frag_fragColor = OpVariable %op_v4f32 Output\n"
+               "%frag_vtxColor = OpVariable %ip_v4f32 Input\n"
+
+               "; Vertex Entry\n"
+               "%vert_main = OpFunction %void None %fun\n"
+               "%vert_label = OpLabel\n"
+               "%vert_tmp_position = OpLoad %v4f32 %vert_Position\n"
+               "OpStore %vert_vtxPosition %vert_tmp_position\n"
+               "%vert_tmp_color = OpLoad %v4f32 %vert_color\n"
+               "OpStore %vert_vtxColor %vert_tmp_color\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "; Geometry Entry\n"
+               "%geom_main = OpFunction %void None %fun\n"
+               "%geom_label = OpLabel\n"
+               "%geom_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_0 %c_i32_0\n"
+               "%geom_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_1 %c_i32_0\n"
+               "%geom_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_2 %c_i32_0\n"
+               "%geom_in_position_0 = OpLoad %v4f32 %geom_gl_in_0_gl_position\n"
+               "%geom_in_position_1 = OpLoad %v4f32 %geom_gl_in_1_gl_position\n"
+               "%geom_in_position_2 = OpLoad %v4f32 %geom_gl_in_2_gl_position \n"
+               "%geom_in_color_0_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_0\n"
+               "%geom_in_color_1_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_1\n"
+               "%geom_in_color_2_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_2\n"
+               "%geom_in_color_0 = OpLoad %v4f32 %geom_in_color_0_ptr\n"
+               "%geom_in_color_1 = OpLoad %v4f32 %geom_in_color_1_ptr\n"
+               "%geom_in_color_2 = OpLoad %v4f32 %geom_in_color_2_ptr\n"
+               "OpStore %geom_out_gl_position %geom_in_position_0\n"
+               "OpStore %geom_out_color %geom_in_color_0\n"
+               "OpEmitVertex\n"
+               "OpStore %geom_out_gl_position %geom_in_position_1\n"
+               "OpStore %geom_out_color %geom_in_color_1\n"
+               "OpEmitVertex\n"
+               "OpStore %geom_out_gl_position %geom_in_position_2\n"
+               "OpStore %geom_out_color %geom_in_color_2\n"
+               "OpEmitVertex\n"
+               "OpEndPrimitive\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "; Tessellation Control Entry\n"
+               "%tessc_main = OpFunction %void None %fun\n"
+               "%tessc_label = OpLabel\n"
+               "%tessc_invocation_id = OpLoad %i32 %tessc_gl_InvocationID\n"
+               "%tessc_in_color_ptr = OpAccessChain %ip_v4f32 %tessc_in_color %tessc_invocation_id\n"
+               "%tessc_in_position_ptr = OpAccessChain %ip_v4f32 %tessc_in_position %tessc_invocation_id\n"
+               "%tessc_in_color_val = OpLoad %v4f32 %tessc_in_color_ptr\n"
+               "%tessc_in_position_val = OpLoad %v4f32 %tessc_in_position_ptr\n"
+               "%tessc_out_color_ptr = OpAccessChain %op_v4f32 %tessc_out_color %tessc_invocation_id\n"
+               "%tessc_out_position_ptr = OpAccessChain %op_v4f32 %tessc_out_position %tessc_invocation_id\n"
+               "OpStore %tessc_out_color_ptr %tessc_in_color_val\n"
+               "OpStore %tessc_out_position_ptr %tessc_in_position_val\n"
+               "%tessc_is_first_invocation = OpIEqual %bool %tessc_invocation_id %c_i32_0\n"
+               "OpSelectionMerge %tessc_merge_label None\n"
+               "OpBranchConditional %tessc_is_first_invocation %tessc_first_invocation %tessc_merge_label\n"
+               "%tessc_first_invocation = OpLabel\n"
+               "%tessc_tess_outer_0 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_0\n"
+               "%tessc_tess_outer_1 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_1\n"
+               "%tessc_tess_outer_2 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_2\n"
+               "%tessc_tess_inner = OpAccessChain %op_f32 %tessc_gl_TessLevelInner %c_i32_0\n"
+               "OpStore %tessc_tess_outer_0 %c_f32_1\n"
+               "OpStore %tessc_tess_outer_1 %c_f32_1\n"
+               "OpStore %tessc_tess_outer_2 %c_f32_1\n"
+               "OpStore %tessc_tess_inner %c_f32_1\n"
+               "OpBranch %tessc_merge_label\n"
+               "%tessc_merge_label = OpLabel\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "; Tessellation Evaluation Entry\n"
+               "%tesse_main = OpFunction %void None %fun\n"
+               "%tesse_label = OpLabel\n"
+               "%tesse_tc_0_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_0\n"
+               "%tesse_tc_1_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_1\n"
+               "%tesse_tc_2_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_2\n"
+               "%tesse_tc_0 = OpLoad %f32 %tesse_tc_0_ptr\n"
+               "%tesse_tc_1 = OpLoad %f32 %tesse_tc_1_ptr\n"
+               "%tesse_tc_2 = OpLoad %f32 %tesse_tc_2_ptr\n"
+               "%tesse_in_pos_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_0\n"
+               "%tesse_in_pos_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_1\n"
+               "%tesse_in_pos_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_2\n"
+               "%tesse_in_pos_0 = OpLoad %v4f32 %tesse_in_pos_0_ptr\n"
+               "%tesse_in_pos_1 = OpLoad %v4f32 %tesse_in_pos_1_ptr\n"
+               "%tesse_in_pos_2 = OpLoad %v4f32 %tesse_in_pos_2_ptr\n"
+               "%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %BP_tc_0 %tesse_in_pos_0\n"
+               "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %BP_tc_1 %tesse_in_pos_1\n"
+               "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %BP_tc_2 %tesse_in_pos_2\n"
+               "%tesse_out_pos_ptr = OpAccessChain %op_v4f32 %tesse_stream %c_i32_0\n"
+               "%tesse_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse_in_pos_0_weighted %tesse_in_pos_1_weighted\n"
+               "%tesse_computed_out = OpFAdd %v4f32 %tesse_in_pos_0_plus_pos_1 %tesse_in_pos_2_weighted\n"
+               "OpStore %tesse_out_pos_ptr %tesse_computed_out\n"
+               "%tesse_in_clr_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_0\n"
+               "%tesse_in_clr_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_1\n"
+               "%tesse_in_clr_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_2\n"
+               "%tesse_in_clr_0 = OpLoad %v4f32 %tesse_in_clr_0_ptr\n"
+               "%tesse_in_clr_1 = OpLoad %v4f32 %tesse_in_clr_1_ptr\n"
+               "%tesse_in_clr_2 = OpLoad %v4f32 %tesse_in_clr_2_ptr\n"
+               "%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_0 %tesse_in_clr_0\n"
+               "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_1 %tesse_in_clr_1\n"
+               "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_2 %tesse_in_clr_2\n"
+               "%tesse_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse_in_clr_0_weighted %tesse_in_clr_1_weighted\n"
+               "%tesse_computed_clr = OpFAdd %v4f32 %tesse_in_clr_0_plus_col_1 %tesse_in_clr_2_weighted\n"
+               "OpStore %tesse_out_color %tesse_computed_clr\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "; Fragment Entry\n"
+               "%frag_main = OpFunction %void None %fun\n"
+               "%frag_label_main = OpLabel\n"
+               "%frag_tmp1 = OpLoad %v4f32 %frag_vtxColor\n"
+               "OpStore %frag_fragColor %frag_tmp1\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+}
+
+// This has two shaders of each stage. The first
+// is a passthrough, the second inverts the color.
+void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
+{
+       dst.spirvAsmSources.add("vert") <<
+       // This module contains 2 vertex shaders. One that is a passthrough
+       // and a second that inverts the color of the output (1.0 - color).
+               "OpCapability Shader\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Vertex %main \"vert1\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
+               "OpEntryPoint Vertex %main2 \"vert2\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
+
+               "OpName %main \"frag1\"\n"
+               "OpName %main2 \"frag2\"\n"
+               "OpName %vtxPosition \"vtxPosition\"\n"
+               "OpName %Position \"position\"\n"
+               "OpName %vtxColor \"vtxColor\"\n"
+               "OpName %color \"color\"\n"
+               "OpName %vertex_id \"gl_VertexID\"\n"
+               "OpName %instance_id \"gl_InstanceID\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+
+               "OpDecorate %vtxPosition Location 2\n"
+               "OpDecorate %Position Location 0\n"
+               "OpDecorate %vtxColor Location 1\n"
+               "OpDecorate %color Location 1\n"
+               "OpDecorate %vertex_id BuiltIn VertexId\n"
+               "OpDecorate %instance_id BuiltIn InstanceId\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+               "%vtxPosition = OpVariable %op_v4f32 Output\n"
+               "%Position = OpVariable %ip_v4f32 Input\n"
+               "%vtxColor = OpVariable %op_v4f32 Output\n"
+               "%color = OpVariable %ip_v4f32 Input\n"
+               "%vertex_id = OpVariable %ip_i32 Input\n"
+               "%instance_id = OpVariable %ip_i32 Input\n"
+
+               "%main = OpFunction %void None %fun\n"
+               "%label = OpLabel\n"
+               "%tmp_position = OpLoad %v4f32 %Position\n"
+               "OpStore %vtxPosition %tmp_position\n"
+               "%tmp_color = OpLoad %v4f32 %color\n"
+               "OpStore %vtxColor %tmp_color\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "%main2 = OpFunction %void None %fun\n"
+               "%label2 = OpLabel\n"
+               "%tmp_position2 = OpLoad %v4f32 %Position\n"
+               "OpStore %vtxPosition %tmp_position2\n"
+               "%tmp_color2 = OpLoad %v4f32 %color\n"
+               "%tmp_color3 = OpFSub %v4f32 %cval %tmp_color2\n"
+               "OpStore %vtxColor %tmp_color3\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+
+       dst.spirvAsmSources.add("frag") <<
+               // This is a single module that contains 2 fragment shaders.
+               // One that passes color through and the other that inverts the output
+               // color (1.0 - color).
+               "OpCapability Shader\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Fragment %main \"frag1\" %vtxColor %fragColor\n"
+               "OpEntryPoint Fragment %main2 \"frag2\" %vtxColor %fragColor\n"
+               "OpExecutionMode %main OriginUpperLeft\n"
+               "OpExecutionMode %main2 OriginUpperLeft\n"
+
+               "OpName %main \"frag1\"\n"
+               "OpName %main2 \"frag2\"\n"
+               "OpName %fragColor \"fragColor\"\n"
+               "OpName %vtxColor \"vtxColor\"\n"
+               "OpDecorate %fragColor Location 0\n"
+               "OpDecorate %vtxColor Location 1\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+               "%fragColor = OpVariable %op_v4f32 Output\n"
+               "%vtxColor = OpVariable %ip_v4f32 Input\n"
+
+               "%main = OpFunction %void None %fun\n"
+               "%label_main = OpLabel\n"
+               "%tmp1 = OpLoad %v4f32 %vtxColor\n"
+               "OpStore %fragColor %tmp1\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "%main2 = OpFunction %void None %fun\n"
+               "%label_main2 = OpLabel\n"
+               "%tmp2 = OpLoad %v4f32 %vtxColor\n"
+               "%tmp3 = OpFSub %v4f32 %cval %tmp2\n"
+               "OpStore %fragColor %tmp3\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+
+       dst.spirvAsmSources.add("geom") <<
+               "OpCapability Geometry\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Geometry %geom1_main \"geom1\" %out_gl_position %gl_in %out_color %in_color\n"
+               "OpEntryPoint Geometry %geom2_main \"geom2\" %out_gl_position %gl_in %out_color %in_color\n"
+               "OpExecutionMode %geom1_main Triangles\n"
+               "OpExecutionMode %geom2_main Triangles\n"
+               "OpExecutionMode %geom1_main Invocations 0\n"
+               "OpExecutionMode %geom2_main Invocations 0\n"
+               "OpExecutionMode %geom1_main OutputTriangleStrip\n"
+               "OpExecutionMode %geom2_main OutputTriangleStrip\n"
+               "OpExecutionMode %geom1_main OutputVertices 3\n"
+               "OpExecutionMode %geom2_main OutputVertices 3\n"
+               "OpName %geom1_main \"geom1\"\n"
+               "OpName %geom2_main \"geom2\"\n"
+               "OpName %per_vertex_in \"gl_PerVertex\"\n"
+               "OpMemberName %per_vertex_in 0 \"gl_Position\"\n"
+               "OpMemberName %per_vertex_in 1 \"gl_PointSize\"\n"
+               "OpMemberName %per_vertex_in 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %per_vertex_in 3 \"gl_CullDistance\"\n"
+               "OpName %gl_in \"gl_in\"\n"
+               "OpName %out_color \"out_color\"\n"
+               "OpName %in_color \"in_color\"\n"
+               "OpDecorate %out_gl_position BuiltIn Position\n"
+               "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
+               "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
+               "OpDecorate %per_vertex_in Block\n"
+               "OpDecorate %out_color Location 1\n"
+               "OpDecorate %out_color Stream 0\n"
+               "OpDecorate %in_color Location 1\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+               "%per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%a3_per_vertex_in = OpTypeArray %per_vertex_in %c_u32_3\n"
+               "%ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
+               "%gl_in = OpVariable %ip_a3_per_vertex_in Input\n"
+               "%out_color = OpVariable %op_v4f32 Output\n"
+               "%in_color = OpVariable %ip_a3v4f32 Input\n"
+               "%out_gl_position = OpVariable %op_v4f32 Output\n"
+
+               "%geom1_main = OpFunction %void None %fun\n"
+               "%geom1_label = OpLabel\n"
+               "%geom1_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
+               "%geom1_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
+               "%geom1_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
+               "%geom1_in_position_0 = OpLoad %v4f32 %geom1_gl_in_0_gl_position\n"
+               "%geom1_in_position_1 = OpLoad %v4f32 %geom1_gl_in_1_gl_position\n"
+               "%geom1_in_position_2 = OpLoad %v4f32 %geom1_gl_in_2_gl_position \n"
+               "%geom1_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+               "%geom1_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+               "%geom1_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+               "%geom1_in_color_0 = OpLoad %v4f32 %geom1_in_color_0_ptr\n"
+               "%geom1_in_color_1 = OpLoad %v4f32 %geom1_in_color_1_ptr\n"
+               "%geom1_in_color_2 = OpLoad %v4f32 %geom1_in_color_2_ptr\n"
+               "OpStore %out_gl_position %geom1_in_position_0\n"
+               "OpStore %out_color %geom1_in_color_0\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom1_in_position_1\n"
+               "OpStore %out_color %geom1_in_color_1\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom1_in_position_2\n"
+               "OpStore %out_color %geom1_in_color_2\n"
+               "OpEmitVertex\n"
+               "OpEndPrimitive\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "%geom2_main = OpFunction %void None %fun\n"
+               "%geom2_label = OpLabel\n"
+               "%geom2_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
+               "%geom2_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
+               "%geom2_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
+               "%geom2_in_position_0 = OpLoad %v4f32 %geom2_gl_in_0_gl_position\n"
+               "%geom2_in_position_1 = OpLoad %v4f32 %geom2_gl_in_1_gl_position\n"
+               "%geom2_in_position_2 = OpLoad %v4f32 %geom2_gl_in_2_gl_position \n"
+               "%geom2_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+               "%geom2_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+               "%geom2_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+               "%geom2_in_color_0 = OpLoad %v4f32 %geom2_in_color_0_ptr\n"
+               "%geom2_in_color_1 = OpLoad %v4f32 %geom2_in_color_1_ptr\n"
+               "%geom2_in_color_2 = OpLoad %v4f32 %geom2_in_color_2_ptr\n"
+               "%geom2_transformed_in_color_0 = OpFSub %v4f32 %cval %geom2_in_color_0\n"
+               "%geom2_transformed_in_color_1 = OpFSub %v4f32 %cval %geom2_in_color_1\n"
+               "%geom2_transformed_in_color_2 = OpFSub %v4f32 %cval %geom2_in_color_2\n"
+               "OpStore %out_gl_position %geom2_in_position_0\n"
+               "OpStore %out_color %geom2_transformed_in_color_0\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom2_in_position_1\n"
+               "OpStore %out_color %geom2_transformed_in_color_1\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom2_in_position_2\n"
+               "OpStore %out_color %geom2_transformed_in_color_2\n"
+               "OpEmitVertex\n"
+               "OpEndPrimitive\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+
+       dst.spirvAsmSources.add("tessc") <<
+               "OpCapability Tessellation\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint TessellationControl %tessc1_main \"tessc1\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
+               "OpEntryPoint TessellationControl %tessc2_main \"tessc2\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
+               "OpExecutionMode %tessc1_main OutputVertices 3\n"
+               "OpExecutionMode %tessc2_main OutputVertices 3\n"
+               "OpName %tessc1_main \"tessc1\"\n"
+               "OpName %tessc2_main \"tessc2\"\n"
+               "OpName %out_color \"out_color\"\n"
+               "OpName %gl_InvocationID \"gl_InvocationID\"\n"
+               "OpName %in_color \"in_color\"\n"
+               "OpName %out_position \"out_position\"\n"
+               "OpName %in_position \"in_position\"\n"
+               "OpName %gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
+               "OpName %gl_TessLevelInner \"gl_TessLevelInner\"\n"
+               "OpDecorate %out_color Location 1\n"
+               "OpDecorate %gl_InvocationID BuiltIn InvocationId\n"
+               "OpDecorate %in_color Location 1\n"
+               "OpDecorate %out_position Location 2\n"
+               "OpDecorate %in_position Location 2\n"
+               "OpDecorate %gl_TessLevelOuter Patch\n"
+               "OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter\n"
+               "OpDecorate %gl_TessLevelInner Patch\n"
+               "OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+               "%out_color = OpVariable %op_a3v4f32 Output\n"
+               "%gl_InvocationID = OpVariable %ip_i32 Input\n"
+               "%in_color = OpVariable %ip_a32v4f32 Input\n"
+               "%out_position = OpVariable %op_a3v4f32 Output\n"
+               "%in_position = OpVariable %ip_a32v4f32 Input\n"
+               "%gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
+               "%gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+
+               "%tessc1_main = OpFunction %void None %fun\n"
+               "%tessc1_label = OpLabel\n"
+               "%tessc1_invocation_id = OpLoad %i32 %gl_InvocationID\n"
+               "%tessc1_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc1_invocation_id\n"
+               "%tessc1_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc1_invocation_id\n"
+               "%tessc1_in_color_val = OpLoad %v4f32 %tessc1_in_color_ptr\n"
+               "%tessc1_in_position_val = OpLoad %v4f32 %tessc1_in_position_ptr\n"
+               "%tessc1_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc1_invocation_id\n"
+               "%tessc1_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc1_invocation_id\n"
+               "OpStore %tessc1_out_color_ptr %tessc1_in_color_val\n"
+               "OpStore %tessc1_out_position_ptr %tessc1_in_position_val\n"
+               "%tessc1_is_first_invocation = OpIEqual %bool %tessc1_invocation_id %c_i32_0\n"
+               "OpSelectionMerge %tessc1_merge_label None\n"
+               "OpBranchConditional %tessc1_is_first_invocation %tessc1_first_invocation %tessc1_merge_label\n"
+               "%tessc1_first_invocation = OpLabel\n"
+               "%tessc1_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
+               "%tessc1_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
+               "%tessc1_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
+               "%tessc1_tess_inner = OpAccessChain %op_f32 %tessc1_gl_TessLevelInner %c_i32_0\n"
+               "OpStore %tessc1_tess_outer_0 %c_f32_1\n"
+               "OpStore %tessc1_tess_outer_1 %c_f32_1\n"
+               "OpStore %tessc1_tess_outer_2 %c_f32_1\n"
+               "OpStore %tessc1_tess_inner %c_f32_1\n"
+               "OpBranch %tessc1_merge_label\n"
+               "%tessc1_merge_label = OpLabel\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "%tessc2_main = OpFunction %void None %fun\n"
+               "%tessc2_label = OpLabel\n"
+               "%tessc2_invocation_id = OpLoad %i32 %gl_InvocationID\n"
+               "%tessc2_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc2_invocation_id\n"
+               "%tessc2_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc2_invocation_id\n"
+               "%tessc2_in_color_val = OpLoad %v4f32 %tessc2_in_color_ptr\n"
+               "%tessc2_in_position_val = OpLoad %v4f32 %tessc2_in_position_ptr\n"
+               "%tessc2_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc2_invocation_id\n"
+               "%tessc2_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc2_invocation_id\n"
+               "%tessc2_transformed_color = OpFSub %v4f32 %cval %tessc2_in_color_val\n"
+               "OpStore %tessc2_out_color_ptr %tessc2_transformed_color\n"
+               "OpStore %tessc2_out_position_ptr %tessc2_in_position_val\n"
+               "%tessc2_is_first_invocation = OpIEqual %bool %tessc2_invocation_id %c_i32_0\n"
+               "OpSelectionMerge %tessc2_merge_label None\n"
+               "OpBranchConditional %tessc2_is_first_invocation %tessc2_first_invocation %tessc2_merge_label\n"
+               "%tessc2_first_invocation = OpLabel\n"
+               "%tessc2_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
+               "%tessc2_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
+               "%tessc2_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
+               "%tessc2_tess_inner = OpAccessChain %op_f32 %tessc2_gl_TessLevelInner %c_i32_0\n"
+               "OpStore %tessc2_tess_outer_0 %c_f32_1\n"
+               "OpStore %tessc2_tess_outer_1 %c_f32_1\n"
+               "OpStore %tessc2_tess_outer_2 %c_f32_1\n"
+               "OpStore %tessc2_tess_inner %c_f32_1\n"
+               "OpBranch %tessc2_merge_label\n"
+               "%tessc2_merge_label = OpLabel\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+
+       dst.spirvAsmSources.add("tesse") <<
+               "OpCapability Tessellation\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint TessellationEvaluation %tesse1_main \"tesse1\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
+               "OpEntryPoint TessellationEvaluation %tesse2_main \"tesse2\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
+               "OpExecutionMode %tesse1_main Triangles\n"
+               "OpExecutionMode %tesse2_main Triangles\n"
+               "OpName %tesse1_main \"tesse1\"\n"
+               "OpName %tesse2_main \"tesse2\"\n"
+               "OpName %per_vertex_out \"gl_PerVertex\"\n"
+               "OpMemberName %per_vertex_out 0 \"gl_Position\"\n"
+               "OpMemberName %per_vertex_out 1 \"gl_PointSize\"\n"
+               "OpMemberName %per_vertex_out 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %per_vertex_out 3 \"gl_CullDistance\"\n"
+               "OpName %stream \"\"\n"
+               "OpName %gl_tessCoord \"gl_TessCoord\"\n"
+               "OpName %in_position \"in_position\"\n"
+               "OpName %out_color \"out_color\"\n"
+               "OpName %in_color \"in_color\"\n"
+               "OpMemberDecorate %per_vertex_out 0 BuiltIn Position\n"
+               "OpMemberDecorate %per_vertex_out 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %per_vertex_out 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %per_vertex_out 3 BuiltIn CullDistance\n"
+               "OpDecorate %per_vertex_out Block\n"
+               "OpDecorate %gl_tessCoord BuiltIn TessCoord\n"
+               "OpDecorate %in_position Location 2\n"
+               "OpDecorate %out_color Location 1\n"
+               "OpDecorate %in_color Location 1\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+               "%per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%op_per_vertex_out = OpTypePointer Output %per_vertex_out\n"
+               "%stream = OpVariable %op_per_vertex_out Output\n"
+               "%gl_tessCoord = OpVariable %ip_v3f32 Input\n"
+               "%in_position = OpVariable %ip_a32v4f32 Input\n"
+               "%out_color = OpVariable %op_v4f32 Output\n"
+               "%in_color = OpVariable %ip_a32v4f32 Input\n"
+
+               "%tesse1_main = OpFunction %void None %fun\n"
+               "%tesse1_label = OpLabel\n"
+               "%tesse1_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
+               "%tesse1_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
+               "%tesse1_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
+               "%tesse1_tc_0 = OpLoad %f32 %tesse1_tc_0_ptr\n"
+               "%tesse1_tc_1 = OpLoad %f32 %tesse1_tc_1_ptr\n"
+               "%tesse1_tc_2 = OpLoad %f32 %tesse1_tc_2_ptr\n"
+               "%tesse1_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
+               "%tesse1_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
+               "%tesse1_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
+               "%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
+               "%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
+               "%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
+               "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %tesse1_in_pos_0\n"
+               "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %tesse1_in_pos_1\n"
+               "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %tesse1_in_pos_2\n"
+               "%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
+               "%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
+               "%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
+               "OpStore %tesse1_out_pos_ptr %tesse1_computed_out\n"
+               "%tesse1_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+               "%tesse1_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+               "%tesse1_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+               "%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
+               "%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
+               "%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
+               "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %in_clr_0\n"
+               "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %in_clr_1\n"
+               "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %in_clr_2\n"
+               "%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
+               "%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
+               "OpStore %out_color %tesse1_computed_clr\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+
+               "%tesse2_main = OpFunction %void None %fun\n"
+               "%tesse2_label = OpLabel\n"
+               "%tesse2_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
+               "%tesse2_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
+               "%tesse2_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
+               "%tesse2_tc_0 = OpLoad %f32 %tesse2_tc_0_ptr\n"
+               "%tesse2_tc_1 = OpLoad %f32 %tesse2_tc_1_ptr\n"
+               "%tesse2_tc_2 = OpLoad %f32 %tesse2_tc_2_ptr\n"
+               "%tesse2_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
+               "%tesse2_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
+               "%tesse2_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
+               "%tesse2_in_pos_0 = OpLoad %v4f32 %tesse2_in_pos_0_ptr\n"
+               "%tesse2_in_pos_1 = OpLoad %v4f32 %tesse2_in_pos_1_ptr\n"
+               "%tesse2_in_pos_2 = OpLoad %v4f32 %tesse2_in_pos_2_ptr\n"
+               "%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %tesse2_in_pos_0\n"
+               "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %tesse2_in_pos_1\n"
+               "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %tesse2_in_pos_2\n"
+               "%tesse2_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
+               "%tesse2_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse2_in_pos_0_weighted %tesse2_in_pos_1_weighted\n"
+               "%tesse2_computed_out = OpFAdd %v4f32 %tesse2_in_pos_0_plus_pos_1 %tesse2_in_pos_2_weighted\n"
+               "OpStore %tesse2_out_pos_ptr %tesse2_computed_out\n"
+               "%tesse2_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
+               "%tesse2_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
+               "%tesse2_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
+               "%tesse2_in_clr_0 = OpLoad %v4f32 %tesse2_in_clr_0_ptr\n"
+               "%tesse2_in_clr_1 = OpLoad %v4f32 %tesse2_in_clr_1_ptr\n"
+               "%tesse2_in_clr_2 = OpLoad %v4f32 %tesse2_in_clr_2_ptr\n"
+               "%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %in_clr_0\n"
+               "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %in_clr_1\n"
+               "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %in_clr_2\n"
+               "%tesse2_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse2_in_clr_0_weighted %tesse2_in_clr_1_weighted\n"
+               "%tesse2_computed_clr = OpFAdd %v4f32 %tesse2_in_clr_0_plus_col_1 %tesse2_in_clr_2_weighted\n"
+               "%tesse2_clr_transformed = OpFSub %v4f32 %cval %tesse2_computed_clr\n"
+               "OpStore %out_color %tesse2_clr_transformed\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+}
+
 // Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
 // Feeds the pipeline a set of colored triangles, which then must occur in the
 // rendered image.  The surface is cleared before executing the pipeline, so
@@ -2471,6 +4584,7 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
                DE_NULL,                                                                                //      const VkAttachmentReference*    pDepthStencilAttachment;
                0u,                                                                                             //      deUint32                                                preserveCount;
                DE_NULL,                                                                                //      const VkAttachmentReference*    pPreserveAttachments;
+
        };
        const VkRenderPassCreateInfo                    renderPassParams                =
        {
@@ -2510,6 +4624,7 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
        };
        const Unique<VkImageView>                               colorAttView                    (createImageView(vk, vkDevice, &colorAttViewParams));
 
+
        // Pipeline layout
        const VkPipelineLayoutCreateInfo                pipelineLayoutParams    =
        {
@@ -2524,10 +4639,48 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
        const Unique<VkPipelineLayout>                  pipelineLayout                  (createPipelineLayout(vk, vkDevice, &pipelineLayoutParams));
 
        // Pipeline
-       vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
-
+       vector<VkPipelineShaderStageCreateInfo>         shaderStageParams;
+       // We need these vectors to make sure that information about specialization constants for each stage can outlive createGraphicsPipeline().
+       vector<vector<VkSpecializationMapEntry> >       specConstantEntries;
+       vector<VkSpecializationInfo>                            specializationInfos;
        createPipelineShaderStages(vk, vkDevice, instance, context, modules, shaderStageParams);
 
+       // And we don't want the reallocation of these vectors to invalidate pointers pointing to their contents.
+       specConstantEntries.reserve(shaderStageParams.size());
+       specializationInfos.reserve(shaderStageParams.size());
+
+       // Patch the specialization info field in PipelineShaderStageCreateInfos.
+       for (vector<VkPipelineShaderStageCreateInfo>::iterator stageInfo = shaderStageParams.begin(); stageInfo != shaderStageParams.end(); ++stageInfo)
+       {
+               const StageToSpecConstantMap::const_iterator stageIt = instance.specConstants.find(stageInfo->stage);
+
+               if (stageIt != instance.specConstants.end())
+               {
+                       const size_t                                            numSpecConstants        = stageIt->second.size();
+                       vector<VkSpecializationMapEntry>        entries;
+                       VkSpecializationInfo                            specInfo;
+
+                       entries.reserve(numSpecConstants);
+
+                       // Only support 32-bit integers as spec constants now. And their constant IDs are numbered sequentially starting from 0.
+                       for (size_t ndx = 0; ndx < numSpecConstants; ++ndx)
+                       {
+                               entries[ndx].constantID = (deUint32)ndx;
+                               entries[ndx].offset             = deUint32(ndx * sizeof(deInt32));
+                               entries[ndx].size               = sizeof(deInt32);
+                       }
+
+                       specConstantEntries.push_back(entries);
+
+                       specInfo.mapEntryCount  = (deUint32)numSpecConstants;
+                       specInfo.pMapEntries    = specConstantEntries.back().data();
+                       specInfo.dataSize               = numSpecConstants * sizeof(deInt32);
+                       specInfo.pData                  = stageIt->second.data();
+                       specializationInfos.push_back(specInfo);
+
+                       stageInfo->pSpecializationInfo = &specializationInfos.back();
+               }
+       }
        const VkPipelineDepthStencilStateCreateInfo     depthStencilParams              =
        {
                VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     //      VkStructureType         sType;
@@ -2618,12 +4771,13 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
                0.0f,                                                                                                           //      float                   slopeScaledDepthBias;
                1.0f,                                                                                                           //      float                   lineWidth;
        };
+       const VkPrimitiveTopology topology = instance.hasTessellation? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
        const VkPipelineInputAssemblyStateCreateInfo    inputAssemblyParams     =
        {
                VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    //      VkStructureType         sType;
                DE_NULL,                                                                                                                //      const void*                     pNext;
                (VkPipelineInputAssemblyStateCreateFlags)0,
-               VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,                                                               //      VkPrimitiveTopology     topology;
+               topology,                                                                                                               //      VkPrimitiveTopology     topology;
                DE_FALSE,                                                                                                               //      deUint32                        primitiveRestartEnable;
        };
        const VkVertexInputBindingDescription           vertexBinding0 =
@@ -2700,6 +4854,7 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
                3u
        };
 
+       const VkPipelineTessellationStateCreateInfo* tessellationInfo   =       instance.hasTessellation? &tessellationState: DE_NULL;
        const VkGraphicsPipelineCreateInfo              pipelineParams                  =
        {
                VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,                //      VkStructureType                                                                 sType;
@@ -2709,7 +4864,7 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
                &shaderStageParams[0],                                                                  //      const VkPipelineShaderStageCreateInfo*                  pStages;
                &vertexInputStateParams,                                                                //      const VkPipelineVertexInputStateCreateInfo*             pVertexInputState;
                &inputAssemblyParams,                                                                   //      const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState;
-               &tessellationState,                                                                             //      const VkPipelineTessellationStateCreateInfo*    pTessellationState;
+               tessellationInfo,                                                                               //      const VkPipelineTessellationStateCreateInfo*    pTessellationState;
                &viewportParams,                                                                                //      const VkPipelineViewportStateCreateInfo*                pViewportState;
                &rasterParams,                                                                                  //      const VkPipelineRasterStateCreateInfo*                  pRasterState;
                &multisampleParams,                                                                             //      const VkPipelineMultisampleStateCreateInfo*             pMultisampleState;
@@ -2970,11 +5125,7 @@ TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instan
        return TestStatus::pass("Rendered output matches input");
 }
 
-void createTestsForAllStages(const std::string& name,
-                                                        const RGBA (&inputColors)[4],
-                                                        const RGBA (&outputColors)[4],
-                                                        const map<string, string>& testCodeFragments,
-                                                        tcu::TestCaseGroup* tests)
+void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const vector<deInt32>& specConstants, tcu::TestCaseGroup* tests)
 {
        const ShaderElement             pipelineStages[]                                =
        {
@@ -2985,49 +5136,2179 @@ void createTestsForAllStages(const std::string& name,
                ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
        };
 
+       StageToSpecConstantMap  specConstantMap;
+
+       specConstantMap[VK_SHADER_STAGE_VERTEX_BIT] = specConstants;
        addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-vert", "", addShaderCodeCustomVertex, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
 
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants;
        addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
 
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants;
        addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
 
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants;
        addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
 
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants;
        addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
+                                                                                                createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
+}
+
+inline void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, tcu::TestCaseGroup* tests)
+{
+       vector<deInt32> noSpecConstants;
+       createTestsForAllStages(name, inputColors, outputColors, testCodeFragments, noSpecConstants, tests);
 }
+
 } // anonymous
 
-tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
+tcu::TestCaseGroup* createOpSourceTests (tcu::TestContext& testCtx)
+{
+       struct NameCodePair { string name, code; };
+       RGBA                                                    defaultColors[4];
+       de::MovePtr<tcu::TestCaseGroup> opSourceTests                   (new tcu::TestCaseGroup(testCtx, "opsource", "OpSource instruction"));
+       const std::string                               opsourceGLSLWithFile    = "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile ";
+       map<string, string>                             fragments                               = passthruFragments();
+       const NameCodePair                              tests[]                                 =
+       {
+               {"unknown", "OpSource Unknown 321"},
+               {"essl", "OpSource ESSL 310"},
+               {"glsl", "OpSource GLSL 450"},
+               {"opencl_cpp", "OpSource OpenCL_CPP 120"},
+               {"opencl_c", "OpSource OpenCL_C 120"},
+               {"multiple", "OpSource GLSL 450\nOpSource GLSL 450"},
+               {"file", opsourceGLSLWithFile},
+               {"source", opsourceGLSLWithFile + "\"void main(){}\""},
+               // Longest possible source string: SPIR-V limits instructions to 65535
+               // words, of which the first 4 are opsourceGLSLWithFile; the rest will
+               // contain 65530 UTF8 characters (one word each) plus one last word
+               // containing 3 ASCII characters and \0.
+               {"longsource", opsourceGLSLWithFile + '"' + makeLongUTF8String(65530) + "ccc" + '"'}
+       };
+
+       getDefaultColors(defaultColors);
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+       {
+               fragments["debug"] = tests[testNdx].code;
+               createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
+       }
+
+       return opSourceTests.release();
+}
+
+tcu::TestCaseGroup* createOpSourceContinuedTests (tcu::TestContext& testCtx)
+{
+       struct NameCodePair { string name, code; };
+       RGBA                                                            defaultColors[4];
+       de::MovePtr<tcu::TestCaseGroup>         opSourceTests           (new tcu::TestCaseGroup(testCtx, "opsourcecontinued", "OpSourceContinued instruction"));
+       map<string, string>                                     fragments                       = passthruFragments();
+       const std::string                                       opsource                        = "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile \"void main(){}\"\n";
+       const NameCodePair                                      tests[]                         =
+       {
+               {"empty", opsource + "OpSourceContinued \"\""},
+               {"short", opsource + "OpSourceContinued \"abcde\""},
+               {"multiple", opsource + "OpSourceContinued \"abcde\"\nOpSourceContinued \"fghij\""},
+               // Longest possible source string: SPIR-V limits instructions to 65535
+               // words, of which the first one is OpSourceContinued/length; the rest
+               // will contain 65533 UTF8 characters (one word each) plus one last word
+               // containing 3 ASCII characters and \0.
+               {"long", opsource + "OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\""}
+       };
+
+       getDefaultColors(defaultColors);
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+       {
+               fragments["debug"] = tests[testNdx].code;
+               createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
+       }
+
+       return opSourceTests.release();
+}
+
+tcu::TestCaseGroup* createOpNoLineTests(tcu::TestContext& testCtx)
 {
-       de::MovePtr<tcu::TestCaseGroup> instructionTests (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
-
-       instructionTests->addChild(createOpNopGroup(testCtx));
-       instructionTests->addChild(createOpLineGroup(testCtx));
-       instructionTests->addChild(createOpNoLineGroup(testCtx));
-       instructionTests->addChild(createOpConstantNullGroup(testCtx));
-       instructionTests->addChild(createOpConstantCompositeGroup(testCtx));
-       instructionTests->addChild(createOpConstantUsageGroup(testCtx));
-       instructionTests->addChild(createOpSourceGroup(testCtx));
-       instructionTests->addChild(createOpSourceExtensionGroup(testCtx));
-       instructionTests->addChild(createDecorationGroupGroup(testCtx));
-       instructionTests->addChild(createOpPhiGroup(testCtx));
-       instructionTests->addChild(createLoopControlGroup(testCtx));
-       instructionTests->addChild(createFunctionControlGroup(testCtx));
-       instructionTests->addChild(createSelectionControlGroup(testCtx));
-       instructionTests->addChild(createBlockOrderGroup(testCtx));
-       instructionTests->addChild(createOpUndefGroup(testCtx));
-       instructionTests->addChild(createOpUnreachableGroup(testCtx));
-
-    RGBA defaultColors[4];
+       RGBA                                                             defaultColors[4];
+       de::MovePtr<tcu::TestCaseGroup>          opLineTests             (new tcu::TestCaseGroup(testCtx, "opNoLine", "OpNoLine instruction"));
+       map<string, string>                                      fragments;
        getDefaultColors(defaultColors);
-       de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "graphics-assembly", "Test the graphics pipeline"));
-       createTestsForAllStages("passthru", defaultColors, defaultColors, passthruFragments(), group.get());
-       instructionTests->addChild(group.release());
+       fragments["debug"]                      =
+               "%name = OpString \"name\"\n";
+
+       fragments["pre_main"]   =
+               "OpNoLine\n"
+               "OpNoLine\n"
+               "OpLine %name 1 1\n"
+               "OpNoLine\n"
+               "OpLine %name 1 1\n"
+               "OpLine %name 1 1\n"
+               "%second_function = OpFunction %v4f32 None %v4f32_function\n"
+               "OpNoLine\n"
+               "OpLine %name 1 1\n"
+               "OpNoLine\n"
+               "OpLine %name 1 1\n"
+               "OpLine %name 1 1\n"
+               "%second_param1 = OpFunctionParameter %v4f32\n"
+               "OpNoLine\n"
+               "OpNoLine\n"
+               "%label_secondfunction = OpLabel\n"
+               "OpNoLine\n"
+               "OpReturnValue %second_param1\n"
+               "OpFunctionEnd\n"
+               "OpNoLine\n"
+               "OpNoLine\n";
+
+       fragments["testfun"]            =
+               // A %test_code function that returns its argument unchanged.
+               "OpNoLine\n"
+               "OpNoLine\n"
+               "OpLine %name 1 1\n"
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "OpNoLine\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "OpNoLine\n"
+               "OpNoLine\n"
+               "%label_testfun = OpLabel\n"
+               "OpNoLine\n"
+               "%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
+               "OpReturnValue %val1\n"
+               "OpFunctionEnd\n"
+               "OpLine %name 1 1\n"
+               "OpNoLine\n";
+
+       createTestsForAllStages("opNoLine", defaultColors, defaultColors, fragments, opLineTests.get());
+
+       return opLineTests.release();
+}
+
+
+tcu::TestCaseGroup* createOpLineTests(tcu::TestContext& testCtx)
+{
+       RGBA                                                                                                    defaultColors[4];
+       de::MovePtr<tcu::TestCaseGroup>                                                 opLineTests                     (new tcu::TestCaseGroup(testCtx, "opLine", "OpLine instruction"));
+       map<string, string>                                                                             fragments;
+       std::vector<std::pair<std::string, std::string> >               problemStrings;
+
+       problemStrings.push_back(std::make_pair<std::string, std::string>("empty_name", ""));
+       problemStrings.push_back(std::make_pair<std::string, std::string>("short_name", "short_name"));
+       problemStrings.push_back(std::make_pair<std::string, std::string>("long_name", makeLongUTF8String(65530) + "ccc"));
+       getDefaultColors(defaultColors);
+
+       fragments["debug"]                      =
+               "%other_name = OpString \"other_name\"\n";
+
+       fragments["pre_main"]   =
+               "OpLine %file_name 32 0\n"
+               "OpLine %file_name 32 32\n"
+               "OpLine %file_name 32 40\n"
+               "OpLine %other_name 32 40\n"
+               "OpLine %other_name 0 100\n"
+               "OpLine %other_name 0 4294967295\n"
+               "OpLine %other_name 4294967295 0\n"
+               "OpLine %other_name 32 40\n"
+               "OpLine %file_name 0 0\n"
+               "%second_function = OpFunction %v4f32 None %v4f32_function\n"
+               "OpLine %file_name 1 0\n"
+               "%second_param1 = OpFunctionParameter %v4f32\n"
+               "OpLine %file_name 1 3\n"
+               "OpLine %file_name 1 2\n"
+               "%label_secondfunction = OpLabel\n"
+               "OpLine %file_name 0 2\n"
+               "OpReturnValue %second_param1\n"
+               "OpFunctionEnd\n"
+               "OpLine %file_name 0 2\n"
+               "OpLine %file_name 0 2\n";
+
+       fragments["testfun"]            =
+               // A %test_code function that returns its argument unchanged.
+               "OpLine %file_name 1 0\n"
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "OpLine %file_name 16 330\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "OpLine %file_name 14 442\n"
+               "%label_testfun = OpLabel\n"
+               "OpLine %file_name 11 1024\n"
+               "%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
+               "OpLine %file_name 2 97\n"
+               "OpReturnValue %val1\n"
+               "OpFunctionEnd\n"
+               "OpLine %file_name 5 32\n";
+
+       for (size_t i = 0; i < problemStrings.size(); ++i)
+       {
+               map<string, string> testFragments = fragments;
+               testFragments["debug"] += "%file_name = OpString \"" + problemStrings[i].second + "\"\n";
+               createTestsForAllStages(string("opLine") + "-" + problemStrings[i].first, defaultColors, defaultColors, testFragments, opLineTests.get());
+       }
+
+       return opLineTests.release();
+}
+
+tcu::TestCaseGroup* createOpConstantNullTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> opConstantNullTests             (new tcu::TestCaseGroup(testCtx, "opConstantNull", "OpConstantNull instruction"));
+       RGBA                                                    colors[4];
+
+
+       const char                                              functionStart[] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%lbl    = OpLabel\n";
+
+       const char                                              functionEnd[]   =
+               "OpReturnValue %transformed_param\n"
+               "OpFunctionEnd\n";
+
+       struct NameConstantsCode
+       {
+               string name;
+               string constants;
+               string code;
+       };
+
+       NameConstantsCode tests[] =
+       {
+               {
+                       "vec4",
+                       "%cnull = OpConstantNull %v4f32\n",
+                       "%transformed_param = OpFAdd %v4f32 %param1 %cnull\n"
+               },
+               {
+                       "float",
+                       "%cnull = OpConstantNull %f32\n",
+                       "%vp = OpVariable %fp_v4f32 Function\n"
+                       "%v  = OpLoad %v4f32 %vp\n"
+                       "%v0 = OpVectorInsertDynamic %v4f32 %v %cnull %c_i32_0\n"
+                       "%v1 = OpVectorInsertDynamic %v4f32 %v0 %cnull %c_i32_1\n"
+                       "%v2 = OpVectorInsertDynamic %v4f32 %v1 %cnull %c_i32_2\n"
+                       "%v3 = OpVectorInsertDynamic %v4f32 %v2 %cnull %c_i32_3\n"
+                       "%transformed_param = OpFAdd %v4f32 %param1 %v3\n"
+               },
+               {
+                       "bool",
+                       "%cnull             = OpConstantNull %bool\n",
+                       "%v                 = OpVariable %fp_v4f32 Function\n"
+                       "                     OpStore %v %param1\n"
+                       "                     OpSelectionMerge %false_label None\n"
+                       "                     OpBranchConditional %cnull %true_label %false_label\n"
+                       "%true_label        = OpLabel\n"
+                       "                     OpStore %v %c_v4f32_0_5_0_5_0_5_0_5\n"
+                       "                     OpBranch %false_label\n"
+                       "%false_label       = OpLabel\n"
+                       "%transformed_param = OpLoad %v4f32 %v\n"
+               },
+               {
+                       "i32",
+                       "%cnull             = OpConstantNull %i32\n",
+                       "%v                 = OpVariable %fp_v4f32 Function %c_v4f32_0_5_0_5_0_5_0_5\n"
+                       "%b                 = OpIEqual %bool %cnull %c_i32_0\n"
+                       "                     OpSelectionMerge %false_label None\n"
+                       "                     OpBranchConditional %b %true_label %false_label\n"
+                       "%true_label        = OpLabel\n"
+                       "                     OpStore %v %param1\n"
+                       "                     OpBranch %false_label\n"
+                       "%false_label       = OpLabel\n"
+                       "%transformed_param = OpLoad %v4f32 %v\n"
+               },
+               {
+                       "struct",
+                       "%stype             = OpTypeStruct %f32 %v4f32\n"
+                       "%fp_stype          = OpTypePointer Function %stype\n"
+                       "%cnull             = OpConstantNull %stype\n",
+                       "%v                 = OpVariable %fp_stype Function %cnull\n"
+                       "%f                 = OpAccessChain %fp_v4f32 %v %c_i32_1\n"
+                       "%f_val             = OpLoad %v4f32 %f\n"
+                       "%transformed_param = OpFAdd %v4f32 %param1 %f_val\n"
+               },
+               {
+                       "array",
+                       "%a4_v4f32          = OpTypeArray %v4f32 %c_u32_4\n"
+                       "%fp_a4_v4f32       = OpTypePointer Function %a4_v4f32\n"
+                       "%cnull             = OpConstantNull %a4_v4f32\n",
+                       "%v                 = OpVariable %fp_a4_v4f32 Function %cnull\n"
+                       "%f                 = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
+                       "%f1                = OpAccessChain %fp_v4f32 %v %c_u32_1\n"
+                       "%f2                = OpAccessChain %fp_v4f32 %v %c_u32_2\n"
+                       "%f3                = OpAccessChain %fp_v4f32 %v %c_u32_3\n"
+                       "%f_val             = OpLoad %v4f32 %f\n"
+                       "%f1_val            = OpLoad %v4f32 %f1\n"
+                       "%f2_val            = OpLoad %v4f32 %f2\n"
+                       "%f3_val            = OpLoad %v4f32 %f3\n"
+                       "%t0                = OpFAdd %v4f32 %param1 %f_val\n"
+                       "%t1                = OpFAdd %v4f32 %t0 %f1_val\n"
+                       "%t2                = OpFAdd %v4f32 %t1 %f2_val\n"
+                       "%transformed_param = OpFAdd %v4f32 %t2 %f3_val\n"
+               },
+               {
+                       "matrix",
+                       "%mat4x4_f32        = OpTypeMatrix %v4f32 4\n"
+                       "%cnull             = OpConstantNull %mat4x4_f32\n",
+                       // Our null matrix * any vector should result in a zero vector.
+                       "%v                 = OpVectorTimesMatrix %v4f32 %param1 %cnull\n"
+                       "%transformed_param = OpFAdd %v4f32 %param1 %v\n"
+               }
+       };
+
+       getHalfColorsFullAlpha(colors);
+
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
+       {
+               map<string, string> fragments;
+               fragments["pre_main"] = tests[testNdx].constants;
+               fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
+               createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, opConstantNullTests.get());
+       }
+       return opConstantNullTests.release();
+}
+tcu::TestCaseGroup* createOpConstantCompositeTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> opConstantCompositeTests                (new tcu::TestCaseGroup(testCtx, "opConstantComposite", "OpConstantComposite instruction"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors[4];
+
+
+       const char                                              functionStart[]  =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%lbl    = OpLabel\n";
+
+       const char                                              functionEnd[]           =
+               "OpReturnValue %transformed_param\n"
+               "OpFunctionEnd\n";
+
+       struct NameConstantsCode
+       {
+               string name;
+               string constants;
+               string code;
+       };
+
+       NameConstantsCode tests[] =
+       {
+               {
+                       "vec4",
+
+                       "%cval              = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0\n",
+                       "%transformed_param = OpFAdd %v4f32 %param1 %cval\n"
+               },
+               {
+                       "struct",
+
+                       "%stype             = OpTypeStruct %v4f32 %f32\n"
+                       "%fp_stype          = OpTypePointer Function %stype\n"
+                       "%f32_n_1           = OpConstant %f32 -1.0\n"
+                       "%f32_1_5           = OpConstant %f32 !0x3fc00000\n" // +1.5
+                       "%cvec              = OpConstantComposite %v4f32 %f32_1_5 %f32_1_5 %f32_1_5 %c_f32_1\n"
+                       "%cval              = OpConstantComposite %stype %cvec %f32_n_1\n",
+
+                       "%v                 = OpVariable %fp_stype Function %cval\n"
+                       "%vec_ptr           = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
+                       "%f32_ptr           = OpAccessChain %fp_v4f32 %v %c_u32_1\n"
+                       "%vec_val           = OpLoad %v4f32 %vec_ptr\n"
+                       "%f32_val           = OpLoad %v4f32 %f32_ptr\n"
+                       "%tmp1              = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_1 %f32_val\n" // vec4(-1)
+                       "%tmp2              = OpFAdd %v4f32 %tmp1 %param1\n" // param1 + vec4(-1)
+                       "%transformed_param = OpFAdd %v4f32 %tmp2 %vec_val\n" // param1 + vec4(-1) + vec4(1.5, 1.5, 1.5, 1.0)
+               },
+               {
+                       // [1|0|0|0.5] [x] = x + 0.5
+                       // [0|1|0|0.5] [y] = y + 0.5
+                       // [0|0|1|0.5] [z] = z + 0.5
+                       // [0|0|0|1  ] [1] = 1
+                       "matrix",
+
+                       "%mat4x4_f32          = OpTypeMatrix %v4f32 4\n"
+                   "%v4f32_1_0_0_0       = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_0\n"
+                   "%v4f32_0_1_0_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_1 %c_f32_0 %c_f32_0\n"
+                   "%v4f32_0_0_1_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_1 %c_f32_0\n"
+                   "%v4f32_0_5_0_5_0_5_1 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_1\n"
+                       "%cval                = OpConstantComposite %mat4x4_f32 %v4f32_1_0_0_0 %v4f32_0_1_0_0 %v4f32_0_0_1_0 %v4f32_0_5_0_5_0_5_1\n",
+
+                       "%transformed_param   = OpMatrixTimesVector %v4f32 %cval %param1\n"
+               },
+               {
+                       "array",
+
+                       "%c_v4f32_1_1_1_0     = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+                       "%fp_a4f32            = OpTypePointer Function %a4f32\n"
+                       "%f32_n_1             = OpConstant %f32 -1.0\n"
+                       "%f32_1_5             = OpConstant %f32 !0x3fc00000\n" // +1.5
+                       "%carr                = OpConstantComposite %a4f32 %c_f32_0 %f32_n_1 %f32_1_5 %c_f32_0\n",
+
+                       "%v                   = OpVariable %fp_a4f32 Function %carr\n"
+                       "%f                   = OpAccessChain %fp_f32 %v %c_u32_0\n"
+                       "%f1                  = OpAccessChain %fp_f32 %v %c_u32_1\n"
+                       "%f2                  = OpAccessChain %fp_f32 %v %c_u32_2\n"
+                       "%f3                  = OpAccessChain %fp_f32 %v %c_u32_3\n"
+                       "%f_val               = OpLoad %f32 %f\n"
+                       "%f1_val              = OpLoad %f32 %f1\n"
+                       "%f2_val              = OpLoad %f32 %f2\n"
+                       "%f3_val              = OpLoad %f32 %f3\n"
+                       "%ftot1               = OpFAdd %f32 %f_val %f1_val\n"
+                       "%ftot2               = OpFAdd %f32 %ftot1 %f2_val\n"
+                       "%ftot3               = OpFAdd %f32 %ftot2 %f3_val\n"  // 0 - 1 + 1.5 + 0
+                       "%add_vec             = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %ftot3\n"
+                       "%transformed_param   = OpFAdd %v4f32 %param1 %add_vec\n"
+               },
+               {
+                       //
+                       // [
+                       //   {
+                       //      0.0,
+                       //      [ 1.0, 1.0, 1.0, 1.0]
+                       //   },
+                       //   {
+                       //      1.0,
+                       //      [ 0.0, 0.5, 0.0, 0.0]
+                       //   }, //     ^^^
+                       //   {
+                       //      0.0,
+                       //      [ 1.0, 1.0, 1.0, 1.0]
+                       //   }
+                       // ]
+                       "array_of_struct_of_array",
+
+                       "%c_v4f32_1_1_1_0     = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
+                       "%fp_a4f32            = OpTypePointer Function %a4f32\n"
+                       "%stype               = OpTypeStruct %f32 %a4f32\n"
+                       "%a3stype             = OpTypeArray %stype %c_u32_3\n"
+                       "%fp_a3stype          = OpTypePointer Function %a3stype\n"
+                       "%ca4f32_0            = OpConstantComposite %a4f32 %c_f32_0 %c_f32_0_5 %c_f32_0 %c_f32_0\n"
+                       "%ca4f32_1            = OpConstantComposite %a4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+                       "%cstype1             = OpConstantComposite %stype %c_f32_0 %ca4f32_1\n"
+                       "%cstype2             = OpConstantComposite %stype %c_f32_1 %ca4f32_0\n"
+                       "%carr                = OpConstantComposite %a3stype %cstype1 %cstype2 %cstype1",
+
+                       "%v                   = OpVariable %fp_a3stype Function %carr\n"
+                       "%f                   = OpAccessChain %fp_f32 %v %c_u32_1 %c_u32_1 %c_u32_1\n"
+                       "%add_vec             = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %f\n"
+                       "%transformed_param   = OpFAdd %v4f32 %param1 %add_vec\n"
+               }
+       };
+
+       getHalfColorsFullAlpha(inputColors);
+       outputColors[0] = RGBA(255, 255, 255, 255);
+       outputColors[1] = RGBA(255, 127, 127, 255);
+       outputColors[2] = RGBA(127, 255, 127, 255);
+       outputColors[3] = RGBA(127, 127, 255, 255);
+
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
+       {
+               map<string, string> fragments;
+               fragments["pre_main"] = tests[testNdx].constants;
+               fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
+               createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, opConstantCompositeTests.get());
+       }
+       return opConstantCompositeTests.release();
+}
+
+tcu::TestCaseGroup* createSelectionBlockOrderTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                           (new tcu::TestCaseGroup(testCtx, "selection_block_order", "Out-of-order blocks for selection"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors[4];
+       map<string, string>                             fragments;
+
+       // vec4 test_code(vec4 param) {
+       //   vec4 result = param;
+       //   for (int i = 0; i < 4; ++i) {
+       //     if (i == 0) result[i] = 0.;
+       //     else        result[i] = 1. - result[i];
+       //   }
+       //   return result;
+       // }
+       const char                                              function[]                      =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1    = OpFunctionParameter %v4f32\n"
+               "%lbl       = OpLabel\n"
+               "%iptr      = OpVariable %fp_i32 Function\n"
+               "             OpStore %iptr %c_i32_0\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param1\n"
+               "             OpBranch %loop\n"
+
+               // Loop entry block.
+               "%loop      = OpLabel\n"
+               "%ival      = OpLoad %i32 %iptr\n"
+               "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
+               "             OpLoopMerge %exit %loop None\n"
+               "             OpBranchConditional %lt_4 %if_entry %exit\n"
+
+               // Merge block for loop.
+               "%exit      = OpLabel\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+
+               // If-statement entry block.
+               "%if_entry  = OpLabel\n"
+               "%loc       = OpAccessChain %fp_f32 %result %ival\n"
+               "%eq_0      = OpIEqual %bool %ival %c_i32_0\n"
+               "             OpSelectionMerge %if_exit None\n"
+               "             OpBranchConditional %eq_0 %if_true %if_false\n"
+
+               // False branch for if-statement.
+               "%if_false  = OpLabel\n"
+               "%val       = OpLoad %f32 %loc\n"
+               "%sub       = OpFSub %f32 %c_f32_1 %val\n"
+               "             OpStore %loc %sub\n"
+               "             OpBranch %if_exit\n"
+
+               // Merge block for if-statement.
+               "%if_exit   = OpLabel\n"
+               "%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
+               "             OpStore %iptr %ival_next\n"
+               "             OpBranch %loop\n"
+
+               // True branch for if-statement.
+               "%if_true   = OpLabel\n"
+               "             OpStore %loc %c_f32_0\n"
+               "             OpBranch %if_exit\n"
+
+               "             OpFunctionEnd\n";
+
+       fragments["testfun"]    = function;
+
+       inputColors[0]                  = RGBA(127, 127, 127, 0);
+       inputColors[1]                  = RGBA(127, 0,   0,   0);
+       inputColors[2]                  = RGBA(0,   127, 0,   0);
+       inputColors[3]                  = RGBA(0,   0,   127, 0);
+
+       outputColors[0]                 = RGBA(0, 128, 128, 255);
+       outputColors[1]                 = RGBA(0, 255, 255, 255);
+       outputColors[2]                 = RGBA(0, 128, 255, 255);
+       outputColors[3]                 = RGBA(0, 255, 128, 255);
+
+       createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createSwitchBlockOrderTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                           (new tcu::TestCaseGroup(testCtx, "switch_block_order", "Out-of-order blocks for switch"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors[4];
+       map<string, string>                             fragments;
+
+       const char                                              typesAndConstants[]     =
+               "%c_f32_p2  = OpConstant %f32 0.2\n"
+               "%c_f32_p4  = OpConstant %f32 0.4\n"
+               "%c_f32_p6  = OpConstant %f32 0.6\n"
+               "%c_f32_p8  = OpConstant %f32 0.8\n";
+
+       // vec4 test_code(vec4 param) {
+       //   vec4 result = param;
+       //   for (int i = 0; i < 4; ++i) {
+       //     switch (i) {
+       //       case 0: result[i] += .2; break;
+       //       case 1: result[i] += .6; break;
+       //       case 2: result[i] += .4; break;
+       //       case 3: result[i] += .8; break;
+       //       default: break; // unreachable
+       //     }
+       //   }
+       //   return result;
+       // }
+       const char                                              function[]                      =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1    = OpFunctionParameter %v4f32\n"
+               "%lbl       = OpLabel\n"
+               "%iptr      = OpVariable %fp_i32 Function\n"
+               "             OpStore %iptr %c_i32_0\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param1\n"
+               "             OpBranch %loop\n"
+
+               // Loop entry block.
+               "%loop      = OpLabel\n"
+               "%ival      = OpLoad %i32 %iptr\n"
+               "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
+               "             OpLoopMerge %exit %loop None\n"
+               "             OpBranchConditional %lt_4 %switch_entry %exit\n"
+
+               // Merge block for loop.
+               "%exit      = OpLabel\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+
+               // Switch-statement entry block.
+               "%switch_entry   = OpLabel\n"
+               "%loc            = OpAccessChain %fp_f32 %result %ival\n"
+               "%val            = OpLoad %f32 %loc\n"
+               "                  OpSelectionMerge %switch_exit None\n"
+               "                  OpSwitch %ival %switch_default 0 %case0 1 %case1 2 %case2 3 %case3\n"
+
+               "%case2          = OpLabel\n"
+               "%addp4          = OpFAdd %f32 %val %c_f32_p4\n"
+               "                  OpStore %loc %addp4\n"
+               "                  OpBranch %switch_exit\n"
+
+               "%switch_default = OpLabel\n"
+               "                  OpUnreachable\n"
+
+               "%case3          = OpLabel\n"
+               "%addp8          = OpFAdd %f32 %val %c_f32_p8\n"
+               "                  OpStore %loc %addp8\n"
+               "                  OpBranch %switch_exit\n"
+
+               "%case0          = OpLabel\n"
+               "%addp2          = OpFAdd %f32 %val %c_f32_p2\n"
+               "                  OpStore %loc %addp2\n"
+               "                  OpBranch %switch_exit\n"
+
+               // Merge block for switch-statement.
+               "%switch_exit    = OpLabel\n"
+               "%ival_next      = OpIAdd %i32 %ival %c_i32_1\n"
+               "                  OpStore %iptr %ival_next\n"
+               "                  OpBranch %loop\n"
+
+               "%case1          = OpLabel\n"
+               "%addp6          = OpFAdd %f32 %val %c_f32_p6\n"
+               "                  OpStore %loc %addp6\n"
+               "                  OpBranch %switch_exit\n"
+
+               "                  OpFunctionEnd\n";
+
+       fragments["pre_main"]   = typesAndConstants;
+       fragments["testfun"]    = function;
+
+       inputColors[0]                  = RGBA(127, 27,  127, 51);
+       inputColors[1]                  = RGBA(127, 0,   0,   51);
+       inputColors[2]                  = RGBA(0,   27,  0,   51);
+       inputColors[3]                  = RGBA(0,   0,   127, 51);
+
+       outputColors[0]                 = RGBA(178, 180, 229, 255);
+       outputColors[1]                 = RGBA(178, 153, 102, 255);
+       outputColors[2]                 = RGBA(51,  180, 102, 255);
+       outputColors[3]                 = RGBA(51,  153, 229, 255);
+
+       createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createDecorationGroupTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                           (new tcu::TestCaseGroup(testCtx, "decoration_group", "Decoration group tests"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors[4];
+       map<string, string>                             fragments;
+
+       const char                                              decorations[]           =
+               "OpDecorate %array_group         ArrayStride 4\n"
+               "OpDecorate %struct_member_group Offset 0\n"
+               "%array_group         = OpDecorationGroup\n"
+               "%struct_member_group = OpDecorationGroup\n"
+
+               "OpDecorate %group1 RelaxedPrecision\n"
+               "OpDecorate %group3 RelaxedPrecision\n"
+               "OpDecorate %group3 Invariant\n"
+               "OpDecorate %group3 Restrict\n"
+               "%group0 = OpDecorationGroup\n"
+               "%group1 = OpDecorationGroup\n"
+               "%group3 = OpDecorationGroup\n";
+
+       const char                                              typesAndConstants[]     =
+               "%a3f32     = OpTypeArray %f32 %c_u32_3\n"
+               "%struct1   = OpTypeStruct %a3f32\n"
+               "%struct2   = OpTypeStruct %a3f32\n"
+               "%fp_struct1 = OpTypePointer Function %struct1\n"
+               "%fp_struct2 = OpTypePointer Function %struct2\n"
+               "%c_f32_2    = OpConstant %f32 2.\n"
+               "%c_f32_n2   = OpConstant %f32 -2.\n"
+
+               "%c_a3f32_1 = OpConstantComposite %a3f32 %c_f32_1 %c_f32_2 %c_f32_1\n"
+               "%c_a3f32_2 = OpConstantComposite %a3f32 %c_f32_n1 %c_f32_n2 %c_f32_n1\n"
+               "%c_struct1 = OpConstantComposite %struct1 %c_a3f32_1\n"
+               "%c_struct2 = OpConstantComposite %struct2 %c_a3f32_2\n";
+
+       const char                                              function[]                      =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param     = OpFunctionParameter %v4f32\n"
+               "%entry     = OpLabel\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param\n"
+               "%v_struct1 = OpVariable %fp_struct1 Function\n"
+               "             OpStore %v_struct1 %c_struct1\n"
+               "%v_struct2 = OpVariable %fp_struct2 Function\n"
+               "             OpStore %v_struct2 %c_struct2\n"
+               "%ptr1      = OpAccessChain %fp_f32 %v_struct1 %c_i32_0 %c_i32_1\n"
+               "%val1      = OpLoad %f32 %ptr1\n"
+               "%ptr2      = OpAccessChain %fp_f32 %v_struct2 %c_i32_0 %c_i32_2\n"
+               "%val2      = OpLoad %f32 %ptr2\n"
+               "%addvalues = OpFAdd %f32 %val1 %val2\n"
+               "%ptr       = OpAccessChain %fp_f32 %result %c_i32_1\n"
+               "%val       = OpLoad %f32 %ptr\n"
+               "%addresult = OpFAdd %f32 %addvalues %val\n"
+               "             OpStore %ptr %addresult\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+               "             OpFunctionEnd\n";
+
+       struct CaseNameDecoration
+       {
+               string name;
+               string decoration;
+       };
+
+       CaseNameDecoration tests[] =
+       {
+               {
+                       "same_decoration_group_on_multiple_types",
+                       "OpGroupMemberDecorate %struct_member_group %struct1 0 %struct2 0\n"
+               },
+               {
+                       "empty_decoration_group",
+                       "OpGroupDecorate %group0      %a3f32\n"
+                       "OpGroupDecorate %group0      %result\n"
+               },
+               {
+                       "one_element_decoration_group",
+                       "OpGroupDecorate %array_group %a3f32\n"
+               },
+               {
+                       "multiple_elements_decoration_group",
+                       "OpGroupDecorate %group3      %v_struct1\n"
+               },
+               {
+                       "multiple_decoration_groups_on_same_variable",
+                       "OpGroupDecorate %group0      %v_struct2\n"
+                       "OpGroupDecorate %group1      %v_struct2\n"
+                       "OpGroupDecorate %group3      %v_struct2\n"
+               },
+               {
+                       "same_decoration_group_multiple_times",
+                       "OpGroupDecorate %group1      %addvalues\n"
+                       "OpGroupDecorate %group1      %addvalues\n"
+                       "OpGroupDecorate %group1      %addvalues\n"
+               },
+
+       };
+
+       getHalfColorsFullAlpha(inputColors);
+       getHalfColorsFullAlpha(outputColors);
+
+       for (size_t idx = 0; idx < (sizeof(tests) / sizeof(tests[0])); ++idx)
+       {
+               fragments["decoration"] = decorations + tests[idx].decoration;
+               fragments["pre_main"]   = typesAndConstants;
+               fragments["testfun"]    = function;
+
+               createTestsForAllStages(tests[idx].name, inputColors, outputColors, fragments, group.get());
+       }
+
+       return group.release();
+}
+
+struct SpecConstantTwoIntGraphicsCase
+{
+       const char*             caseName;
+       const char*             scDefinition0;
+       const char*             scDefinition1;
+       const char*             scResultType;
+       const char*             scOperation;
+       deInt32                 scActualValue0;
+       deInt32                 scActualValue1;
+       const char*             resultOperation;
+       RGBA                    expectedColors[4];
+
+                                       SpecConstantTwoIntGraphicsCase (const char* name,
+                                                                                       const char* definition0,
+                                                                                       const char* definition1,
+                                                                                       const char* resultType,
+                                                                                       const char* operation,
+                                                                                       deInt32         value0,
+                                                                                       deInt32         value1,
+                                                                                       const char* resultOp,
+                                                                                       const RGBA      (&output)[4])
+                                               : caseName                      (name)
+                                               , scDefinition0         (definition0)
+                                               , scDefinition1         (definition1)
+                                               , scResultType          (resultType)
+                                               , scOperation           (operation)
+                                               , scActualValue0        (value0)
+                                               , scActualValue1        (value1)
+                                               , resultOperation       (resultOp)
+       {
+               expectedColors[0] = output[0];
+               expectedColors[1] = output[1];
+               expectedColors[2] = output[2];
+               expectedColors[3] = output[3];
+       }
+};
+
+tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                           (new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
+       vector<SpecConstantTwoIntGraphicsCase>  cases;
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors0[4];
+       RGBA                                                    outputColors1[4];
+       RGBA                                                    outputColors2[4];
+
+       const char      decorations1[]                  =
+               "OpDecorate %sc_0  SpecId 0\n"
+               "OpDecorate %sc_1  SpecId 1\n";
+
+       const char      typesAndConstants1[]    =
+               "%sc_0      = OpSpecConstant${SC_DEF0}\n"
+               "%sc_1      = OpSpecConstant${SC_DEF1}\n"
+               "%sc_op     = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n";
+
+       const char      function1[]                             =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param     = OpFunctionParameter %v4f32\n"
+               "%label     = OpLabel\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param\n"
+               "%gen       = ${GEN_RESULT}\n"
+               "%index     = OpIAdd %i32 %gen %c_i32_1\n"
+               "%loc       = OpAccessChain %fp_f32 %result %index\n"
+               "%val       = OpLoad %f32 %loc\n"
+               "%add       = OpFAdd %f32 %val %c_f32_0_5\n"
+               "             OpStore %loc %add\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+               "             OpFunctionEnd\n";
+
+       inputColors[0] = RGBA(127, 127, 127, 255);
+       inputColors[1] = RGBA(127, 0,   0,   255);
+       inputColors[2] = RGBA(0,   127, 0,   255);
+       inputColors[3] = RGBA(0,   0,   127, 255);
+
+       // Derived from inputColors[x] by adding 128 to inputColors[x][0].
+       outputColors0[0] = RGBA(255, 127, 127, 255);
+       outputColors0[1] = RGBA(255, 0,   0,   255);
+       outputColors0[2] = RGBA(128, 127, 0,   255);
+       outputColors0[3] = RGBA(128, 0,   127, 255);
+
+       // Derived from inputColors[x] by adding 128 to inputColors[x][1].
+       outputColors1[0] = RGBA(127, 255, 127, 255);
+       outputColors1[1] = RGBA(127, 128, 0,   255);
+       outputColors1[2] = RGBA(0,   255, 0,   255);
+       outputColors1[3] = RGBA(0,   128, 127, 255);
+
+       // Derived from inputColors[x] by adding 128 to inputColors[x][2].
+       outputColors2[0] = RGBA(127, 127, 255, 255);
+       outputColors2[1] = RGBA(127, 0,   128, 255);
+       outputColors2[2] = RGBA(0,   127, 128, 255);
+       outputColors2[3] = RGBA(0,   0,   255, 255);
+
+       const char addZeroToSc[]                = "OpIAdd %i32 %c_i32_0 %sc_op";
+       const char selectTrueUsingSc[]  = "OpSelect %i32 %sc_op %c_i32_1 %c_i32_0";
+       const char selectFalseUsingSc[] = "OpSelect %i32 %sc_op %c_i32_0 %c_i32_1";
+
+       cases.push_back(SpecConstantTwoIntGraphicsCase("iadd",                                  " %i32 0",              " %i32 0",              "%i32",         "IAdd                 %sc_0 %sc_1",                             19,             -20,    addZeroToSc,            outputColors0));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("isub",                                  " %i32 0",              " %i32 0",              "%i32",         "ISub                 %sc_0 %sc_1",                             19,             20,             addZeroToSc,            outputColors0));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("imul",                                  " %i32 0",              " %i32 0",              "%i32",         "IMul                 %sc_0 %sc_1",                             -1,             -1,             addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("sdiv",                                  " %i32 0",              " %i32 0",              "%i32",         "SDiv                 %sc_0 %sc_1",                             -126,   126,    addZeroToSc,            outputColors0));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("udiv",                                  " %i32 0",              " %i32 0",              "%i32",         "UDiv                 %sc_0 %sc_1",                             126,    126,    addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("srem",                                  " %i32 0",              " %i32 0",              "%i32",         "SRem                 %sc_0 %sc_1",                             -3,             2,              addZeroToSc,            outputColors0));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("smod",                                  " %i32 0",              " %i32 0",              "%i32",         "SMod                 %sc_0 %sc_1",                             -3,             2,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("umod",                                  " %i32 0",              " %i32 0",              "%i32",         "UMod                 %sc_0 %sc_1",                             1001,   500,    addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseand",                    " %i32 0",              " %i32 0",              "%i32",         "BitwiseAnd           %sc_0 %sc_1",                             0x33,   0x0d,   addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseor",                             " %i32 0",              " %i32 0",              "%i32",         "BitwiseOr            %sc_0 %sc_1",                             0,              1,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("bitwisexor",                    " %i32 0",              " %i32 0",              "%i32",         "BitwiseAnd           %sc_0 %sc_1",                             0x2e,   0x2f,   addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightlogical",             " %i32 0",              " %i32 0",              "%i32",         "ShiftRightLogical    %sc_0 %sc_1",                             2,              1,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightarithmetic",  " %i32 0",              " %i32 0",              "%i32",         "ShiftRightArithmetic %sc_0 %sc_1",                             -4,             2,              addZeroToSc,            outputColors0));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("shiftleftlogical",              " %i32 0",              " %i32 0",              "%i32",         "ShiftLeftLogical     %sc_0 %sc_1",                             1,              0,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("slessthan",                             " %i32 0",              " %i32 0",              "%bool",        "SLessThan            %sc_0 %sc_1",                             -20,    -10,    selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthan",                             " %i32 0",              " %i32 0",              "%bool",        "ULessThan            %sc_0 %sc_1",                             10,             20,             selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthan",                  " %i32 0",              " %i32 0",              "%bool",        "SGreaterThan         %sc_0 %sc_1",                             -1000,  50,             selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthan",                  " %i32 0",              " %i32 0",              "%bool",        "UGreaterThan         %sc_0 %sc_1",                             10,             5,              selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("slessthanequal",                " %i32 0",              " %i32 0",              "%bool",        "SLessThanEqual       %sc_0 %sc_1",                             -10,    -10,    selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthanequal",                " %i32 0",              " %i32 0",              "%bool",        "ULessThanEqual       %sc_0 %sc_1",                             50,             100,    selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthanequal",             " %i32 0",              " %i32 0",              "%bool",        "SGreaterThanEqual    %sc_0 %sc_1",                             -1000,  50,             selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthanequal",             " %i32 0",              " %i32 0",              "%bool",        "UGreaterThanEqual    %sc_0 %sc_1",                             10,             10,             selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("iequal",                                " %i32 0",              " %i32 0",              "%bool",        "IEqual               %sc_0 %sc_1",                             42,             24,             selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("logicaland",                    "True %bool",   "True %bool",   "%bool",        "LogicalAnd           %sc_0 %sc_1",                             0,              1,              selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("logicalor",                             "False %bool",  "False %bool",  "%bool",        "LogicalOr            %sc_0 %sc_1",                             1,              0,              selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("logicalequal",                  "True %bool",   "True %bool",   "%bool",        "LogicalEqual         %sc_0 %sc_1",                             0,              1,              selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnotequal",               "False %bool",  "False %bool",  "%bool",        "LogicalNotEqual      %sc_0 %sc_1",                             1,              0,              selectTrueUsingSc,      outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("snegate",                               " %i32 0",              " %i32 0",              "%i32",         "SNegate              %sc_0",                                   -1,             0,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("not",                                   " %i32 0",              " %i32 0",              "%i32",         "Not                  %sc_0",                                   -2,             0,              addZeroToSc,            outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnot",                    "False %bool",  "False %bool",  "%bool",        "LogicalNot           %sc_0",                                   1,              0,              selectFalseUsingSc,     outputColors2));
+       cases.push_back(SpecConstantTwoIntGraphicsCase("select",                                "False %bool",  " %i32 0",              "%i32",         "Select               %sc_0 %sc_1 %c_i32_0",    1,              1,              addZeroToSc,            outputColors2));
+       // OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
+       // \todo[2015-12-1 antiagainst] OpQuantizeToF16
+
+       for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+       {
+               map<string, string>     specializations;
+               map<string, string>     fragments;
+               vector<deInt32>         specConstants;
+
+               specializations["SC_DEF0"]                      = cases[caseNdx].scDefinition0;
+               specializations["SC_DEF1"]                      = cases[caseNdx].scDefinition1;
+               specializations["SC_RESULT_TYPE"]       = cases[caseNdx].scResultType;
+               specializations["SC_OP"]                        = cases[caseNdx].scOperation;
+               specializations["GEN_RESULT"]           = cases[caseNdx].resultOperation;
+
+               fragments["decoration"]                         = tcu::StringTemplate(decorations1).specialize(specializations);
+               fragments["pre_main"]                           = tcu::StringTemplate(typesAndConstants1).specialize(specializations);
+               fragments["testfun"]                            = tcu::StringTemplate(function1).specialize(specializations);
+
+               specConstants.push_back(cases[caseNdx].scActualValue0);
+               specConstants.push_back(cases[caseNdx].scActualValue1);
+
+               createTestsForAllStages(cases[caseNdx].caseName, inputColors, cases[caseNdx].expectedColors, fragments, specConstants, group.get());
+       }
+
+       const char      decorations2[]                  =
+               "OpDecorate %sc_0  SpecId 0\n"
+               "OpDecorate %sc_1  SpecId 1\n"
+               "OpDecorate %sc_2  SpecId 2\n";
+
+       const char      typesAndConstants2[]    =
+               "%v3i32     = OpTypeVector %i32 3\n"
+
+               "%sc_0      = OpSpecConstant %i32 0\n"
+               "%sc_1      = OpSpecConstant %i32 0\n"
+               "%sc_2      = OpSpecConstant %i32 0\n"
+
+               "%vec3_0      = OpConstantComposite %v3i32 %c_i32_0 %c_i32_0 %c_i32_0\n"
+               "%sc_vec3_0   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_0        %vec3_0    0\n"     // (sc_0, 0, 0)
+               "%sc_vec3_1   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_1        %vec3_0    1\n"     // (0, sc_1, 0)
+               "%sc_vec3_2   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_2        %vec3_0    2\n"     // (0, 0, sc_2)
+               "%sc_vec3_01  = OpSpecConstantOp %v3i32 VectorShuffle    %sc_vec3_0   %sc_vec3_1 1 0 4\n" // (0,    sc_0, sc_1)
+               "%sc_vec3_012 = OpSpecConstantOp %v3i32 VectorShuffle    %sc_vec3_01  %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
+               "%sc_ext_0    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            0\n"     // sc_2
+               "%sc_ext_1    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            1\n"     // sc_0
+               "%sc_ext_2    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            2\n"     // sc_1
+               "%sc_sub      = OpSpecConstantOp %i32   ISub             %sc_ext_0    %sc_ext_1\n"        // (sc_2 - sc_0)
+               "%sc_final    = OpSpecConstantOp %i32   IMul             %sc_sub      %sc_ext_2\n";       // (sc_2 - sc_0) * sc_1
+
+       const char      function2[]                             =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param     = OpFunctionParameter %v4f32\n"
+               "%label     = OpLabel\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param\n"
+               "%loc       = OpAccessChain %fp_f32 %result %sc_final\n"
+               "%val       = OpLoad %f32 %loc\n"
+               "%add       = OpFAdd %f32 %val %c_f32_0_5\n"
+               "             OpStore %loc %add\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+               "             OpFunctionEnd\n";
+
+       map<string, string>     fragments;
+       vector<deInt32>         specConstants;
+
+       fragments["decoration"] = decorations2;
+       fragments["pre_main"]   = typesAndConstants2;
+       fragments["testfun"]    = function2;
+
+       specConstants.push_back(56789);
+       specConstants.push_back(-2);
+       specConstants.push_back(56788);
+
+       createTestsForAllStages("vector_related", inputColors, outputColors2, fragments, specConstants, group.get());
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createOpPhiTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                           (new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors1[4];
+       RGBA                                                    outputColors2[4];
+       RGBA                                                    outputColors3[4];
+       map<string, string>                             fragments1;
+       map<string, string>                             fragments2;
+       map<string, string>                             fragments3;
+
+       const char      typesAndConstants1[]    =
+               "%c_f32_p2  = OpConstant %f32 0.2\n"
+               "%c_f32_p4  = OpConstant %f32 0.4\n"
+               "%c_f32_p6  = OpConstant %f32 0.6\n"
+               "%c_f32_p8  = OpConstant %f32 0.8\n";
+
+       // vec4 test_code(vec4 param) {
+       //   vec4 result = param;
+       //   for (int i = 0; i < 4; ++i) {
+       //     float operand;
+       //     switch (i) {
+       //       case 0: operand = .2; break;
+       //       case 1: operand = .6; break;
+       //       case 2: operand = .4; break;
+       //       case 3: operand = .0; break;
+       //       default: break; // unreachable
+       //     }
+       //     result[i] += operand;
+       //   }
+       //   return result;
+       // }
+       const char      function1[]                             =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1    = OpFunctionParameter %v4f32\n"
+               "%lbl       = OpLabel\n"
+               "%iptr      = OpVariable %fp_i32 Function\n"
+               "             OpStore %iptr %c_i32_0\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param1\n"
+               "             OpBranch %loop\n"
+
+               "%loop      = OpLabel\n"
+               "%ival      = OpLoad %i32 %iptr\n"
+               "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
+               "             OpLoopMerge %exit %loop None\n"
+               "             OpBranchConditional %lt_4 %entry %exit\n"
+
+               "%entry     = OpLabel\n"
+               "%loc       = OpAccessChain %fp_f32 %result %ival\n"
+               "%val       = OpLoad %f32 %loc\n"
+               "             OpSelectionMerge %phi None\n"
+               "             OpSwitch %ival %default 0 %case0 1 %case1 2 %case2 3 %case3\n"
+
+               "%case0     = OpLabel\n"
+               "             OpBranch %phi\n"
+               "%case1     = OpLabel\n"
+               "             OpBranch %phi\n"
+               "%case2     = OpLabel\n"
+               "             OpBranch %phi\n"
+               "%case3     = OpLabel\n"
+               "             OpBranch %phi\n"
+
+               "%default   = OpLabel\n"
+               "             OpUnreachable\n"
+
+               "%phi       = OpLabel\n"
+               "%operand   = OpPhi %f32 %c_f32_p4 %case2 %c_f32_p6 %case1 %c_f32_p2 %case0 %c_f32_0 %case3\n" // not in the order of blocks
+               "%add       = OpFAdd %f32 %val %operand\n"
+               "             OpStore %loc %add\n"
+               "%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
+               "             OpStore %iptr %ival_next\n"
+               "             OpBranch %loop\n"
+
+               "%exit      = OpLabel\n"
+               "%ret       = OpLoad %v4f32 %result\n"
+               "             OpReturnValue %ret\n"
+
+               "             OpFunctionEnd\n";
+
+       fragments1["pre_main"]  = typesAndConstants1;
+       fragments1["testfun"]   = function1;
+
+       getHalfColorsFullAlpha(inputColors);
+
+       outputColors1[0]                = RGBA(178, 180, 229, 255);
+       outputColors1[1]                = RGBA(178, 153, 102, 255);
+       outputColors1[2]                = RGBA(51,  180, 102, 255);
+       outputColors1[3]                = RGBA(51,  153, 229, 255);
+
+       createTestsForAllStages("out_of_order", inputColors, outputColors1, fragments1, group.get());
+
+       const char      typesAndConstants2[]    =
+               "%c_f32_p2  = OpConstant %f32 0.2\n";
+
+       // Add .4 to the second element of the given parameter.
+       const char      function2[]                             =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param     = OpFunctionParameter %v4f32\n"
+               "%entry     = OpLabel\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param\n"
+               "%loc       = OpAccessChain %fp_f32 %result %c_i32_1\n"
+               "%val       = OpLoad %f32 %loc\n"
+               "             OpBranch %phi\n"
+
+               "%phi        = OpLabel\n"
+               "%step       = OpPhi %i32 %c_i32_0  %entry %step_next  %phi\n"
+               "%accum      = OpPhi %f32 %val      %entry %accum_next %phi\n"
+               "%step_next  = OpIAdd %i32 %step  %c_i32_1\n"
+               "%accum_next = OpFAdd %f32 %accum %c_f32_p2\n"
+               "%still_loop = OpSLessThan %bool %step %c_i32_2\n"
+               "              OpLoopMerge %exit %phi None\n"
+               "              OpBranchConditional %still_loop %phi %exit\n"
+
+               "%exit       = OpLabel\n"
+               "              OpStore %loc %accum\n"
+               "%ret        = OpLoad %v4f32 %result\n"
+               "              OpReturnValue %ret\n"
+
+               "              OpFunctionEnd\n";
+
+       fragments2["pre_main"]  = typesAndConstants2;
+       fragments2["testfun"]   = function2;
+
+       outputColors2[0]                        = RGBA(127, 229, 127, 255);
+       outputColors2[1]                        = RGBA(127, 102, 0,   255);
+       outputColors2[2]                        = RGBA(0,   229, 0,   255);
+       outputColors2[3]                        = RGBA(0,   102, 127, 255);
+
+       createTestsForAllStages("induction", inputColors, outputColors2, fragments2, group.get());
+
+       const char      typesAndConstants3[]    =
+               "%true      = OpConstantTrue %bool\n"
+               "%false     = OpConstantFalse %bool\n"
+               "%c_f32_p2  = OpConstant %f32 0.2\n";
+
+       // Swap the second and the third element of the given parameter.
+       const char      function3[]                             =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param     = OpFunctionParameter %v4f32\n"
+               "%entry     = OpLabel\n"
+               "%result    = OpVariable %fp_v4f32 Function\n"
+               "             OpStore %result %param\n"
+               "%a_loc     = OpAccessChain %fp_f32 %result %c_i32_1\n"
+               "%a_init    = OpLoad %f32 %a_loc\n"
+               "%b_loc     = OpAccessChain %fp_f32 %result %c_i32_2\n"
+               "%b_init    = OpLoad %f32 %b_loc\n"
+               "             OpBranch %phi\n"
+
+               "%phi        = OpLabel\n"
+               "%still_loop = OpPhi %bool %true   %entry %false  %phi\n"
+               "%a_next     = OpPhi %f32  %a_init %entry %b_next %phi\n"
+               "%b_next     = OpPhi %f32  %b_init %entry %a_next %phi\n"
+               "              OpLoopMerge %exit %phi None\n"
+               "              OpBranchConditional %still_loop %phi %exit\n"
+
+               "%exit       = OpLabel\n"
+               "              OpStore %a_loc %a_next\n"
+               "              OpStore %b_loc %b_next\n"
+               "%ret        = OpLoad %v4f32 %result\n"
+               "              OpReturnValue %ret\n"
+
+               "              OpFunctionEnd\n";
+
+       fragments3["pre_main"]  = typesAndConstants3;
+       fragments3["testfun"]   = function3;
+
+       outputColors3[0]                        = RGBA(127, 127, 127, 255);
+       outputColors3[1]                        = RGBA(127, 0,   0,   255);
+       outputColors3[2]                        = RGBA(0,   0,   127, 255);
+       outputColors3[3]                        = RGBA(0,   127, 0,   255);
+
+       createTestsForAllStages("swap", inputColors, outputColors3, fragments3, group.get());
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createNoContractionTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
+       RGBA                                                    inputColors[4];
+       RGBA                                                    outputColors[4];
+
+       // With NoContraction, (1 + 2^-23) * (1 - 2^-23) - 1 should be conducted as a multiplication and an addition separately.
+       // For the multiplication, the result is 1 - 2^-46, which is out of the precision range for 32-bit float. (32-bit float
+       // only have 23-bit fraction.) So it will be rounded to 1. Then the final result is 0. On the contrary, the result will
+       // be 2^-46, which is a normalized number perfectly representable as 32-bit float.
+       const char                                              constantsAndTypes[]      =
+               "%c_vec4_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1\n"
+               "%c_vec4_1       = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
+               "%c_f32_1pl2_23  = OpConstant %f32 0x1.000002p+0\n" // 1 + 2^-23
+               "%c_f32_1mi2_23  = OpConstant %f32 0x1.fffffcp-1\n" // 1 - 2^-23
+               ;
+
+       const char                                              function[]       =
+               "%test_code      = OpFunction %v4f32 None %v4f32_function\n"
+               "%param          = OpFunctionParameter %v4f32\n"
+               "%label          = OpLabel\n"
+               "%var1           = OpVariable %fp_f32 Function %c_f32_1pl2_23\n"
+               "%var2           = OpVariable %fp_f32 Function\n"
+               "%red            = OpCompositeExtract %f32 %param 0\n"
+               "%plus_red       = OpFAdd %f32 %c_f32_1mi2_23 %red\n"
+               "                  OpStore %var2 %plus_red\n"
+               "%val1           = OpLoad %f32 %var1\n"
+               "%val2           = OpLoad %f32 %var2\n"
+               "%mul            = OpFMul %f32 %val1 %val2\n"
+               "%add            = OpFAdd %f32 %mul %c_f32_n1\n"
+               "%is0            = OpFOrdEqual %bool %add %c_f32_0\n"
+               "%ret            = OpSelect %v4f32 %is0 %c_vec4_0 %c_vec4_1\n"
+               "                  OpReturnValue %ret\n"
+               "                  OpFunctionEnd\n";
+
+       struct CaseNameDecoration
+       {
+               string name;
+               string decoration;
+       };
+
+
+       CaseNameDecoration tests[] = {
+               {"multiplication",      "OpDecorate %mul NoContraction"},
+               {"addition",            "OpDecorate %add NoContraction"},
+               {"both",                        "OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"},
+       };
+
+       getHalfColorsFullAlpha(inputColors);
+
+       for (deUint8 idx = 0; idx < 4; ++idx)
+       {
+               inputColors[idx].setRed(0);
+               outputColors[idx] = RGBA(0, 0, 0, 255);
+       }
+
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(CaseNameDecoration); ++testNdx)
+       {
+               map<string, string> fragments;
+
+               fragments["decoration"] = tests[testNdx].decoration;
+               fragments["pre_main"] = constantsAndTypes;
+               fragments["testfun"] = function;
+
+               createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, group.get());
+       }
+
+       return group.release();
+}
+
+tcu::TestCaseGroup* createMemoryAccessTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> memoryAccessTests (new tcu::TestCaseGroup(testCtx, "opMemoryAccess", "Memory Semantics"));
+       RGBA                                                    colors[4];
+
+       const char                                              constantsAndTypes[]      =
+               "%c_a2f32_1         = OpConstantComposite %a2f32 %c_f32_1 %c_f32_1\n"
+               "%fp_a2f32          = OpTypePointer Function %a2f32\n"
+               "%stype             = OpTypeStruct  %v4f32 %a2f32 %f32\n"
+               "%fp_stype          = OpTypePointer Function %stype\n";
+
+       const char                                              function[]       =
+               "%test_code         = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1            = OpFunctionParameter %v4f32\n"
+               "%lbl               = OpLabel\n"
+               "%v1                = OpVariable %fp_v4f32 Function\n"
+               "                     OpStore %v1 %c_v4f32_1_1_1_1\n"
+               "%v2                = OpVariable %fp_a2f32 Function\n"
+               "                     OpStore %v2 %c_a2f32_1\n"
+               "%v3                = OpVariable %fp_f32 Function\n"
+               "                     OpStore %v3 %c_f32_1\n"
+
+               "%v                 = OpVariable %fp_stype Function\n"
+
+               "%vv                = OpVariable %fp_stype Function\n"
+               "%vvv               = OpVariable %fp_f32 Function\n"
+
+               "%p_v4f32          = OpAccessChain %fp_v4_f32 %v %c_u32_0\n"
+               "%p_a2f32          = OpAccessChain %fp_a2f32 %v %c_u32_1\n"
+               "%p_f32            = OpAccessChain %fp_f32 %v %c_u32_2\n"
+               "%v1_v             = OpLoad %v4f32 %v1 ${access_type}\n"
+               "%v2_v             = OpLoad %a2f32 %v2 ${access_type}\n"
+               "%v3_v             = OpLoad %f32 %v3 ${access_type}\n"
+
+               "                    OpStore %p_v4f32 %v1_v ${access_type}\n"
+               "                    OpStore %p_a2f32 %v2_v ${access_type}\n"
+               "                    OpStore %p_f32 %v3_v ${access_type}\n"
+
+               "                    OpCopyMemory %vv %v ${access_type}\n"
+               "                    OpCopyMemory %vvv %p_f32 ${access_type}\n"
+
+               "%p_f32_2          = OpAccessChain %fp_f32 %vv %c_u32_2\n"
+               "%v_f32_2          = OpLoad %f32 %p_f32_2\n"
+               "%v_f32_3          = OpLoad %f32 %vvv\n"
+
+               "%ret1             = OpVectorTimesScalar %v4f32 %param1 %v_f32_2\n"
+               "%ret2             = OpVectorTimesScalar %v4f32 %ret1 %v_f32_3\n"
+               "                    OpReturnValue %ret2\n"
+               "                    OpFunctionEnd\n";
+
+       struct NameMemoryAccess
+       {
+               string name;
+               string accessType;
+       };
+
+
+       NameMemoryAccess tests[] =
+       {
+               { "none", "" },
+               { "volatile", "Volatile" },
+               { "aligned",  "Aligned 1" },
+               { "volatile-aligned",  "Volatile|Aligned 1" },
+               { "nontemporal-aligned",  "Nontemporal|Aligned 1" },
+               { "volatile-nontemporal",  "Volatile|Nontemporal" },
+               { "volatile-nontermporal-aligned",  "Volatile|NonTermporal|Aligned" },
+       };
+
+       getHalfColorsFullAlpha(colors);
+
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameMemoryAccess); ++testNdx)
+       {
+               map<string, string> fragments;
+               map<string, string> memoryAccess;
+               memoryAccess["access_type"] = tests[testNdx].accessType;
+
+               fragments["pre_main"] = constantsAndTypes;
+               fragments["testfun"] = tcu::StringTemplate(function).specialize(memoryAccess);
+               createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, memoryAccessTests.get());
+       }
+       return memoryAccessTests.release();
+}
+tcu::TestCaseGroup* createOpUndefTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup>         opUndefTests             (new tcu::TestCaseGroup(testCtx, "opundef", "Test OpUndef"));
+       RGBA                                                            defaultColors[4];
+       map<string, string>                                     fragments;
+       getDefaultColors(defaultColors);
+
+       // First, simple cases that don't do anything with the OpUndef result.
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %type\n"
+               "OpReturnValue %param1\n"
+               "OpFunctionEnd\n"
+               ;
+       struct NameCodePair { string name, code; };
+       const NameCodePair tests[] =
+       {
+               {"bool", "%type = OpTypeBool"},
+               {"vec2uint32", "%type = OpTypeVector %u32 2"},
+               {"image", "%type = OpTypeImage %f32 2D 0 0 0 0 Unknown"},
+               {"sampler", "%type = OpTypeSampler"},
+               {"sampledimage", "%img = OpTypeImage %f32 2D 0 0 0 0 Unknown\n" "%type = OpTypeSampledImage %img"},
+               {"function", "%type = OpTypeFunction %void %i32 %f32"},
+               {"pointer", "%type = OpTypePointer Function %i32"},
+               {"runtimearray", "%type = OpTypeRuntimeArray %f32"},
+               {"array", "%c_u32_100 = OpConstant %u32 100\n" "%type = OpTypeArray %i32 %c_u32_100"},
+               {"struct", "%type = OpTypeStruct %f32 %i32 %u32"}};
+       for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
+       {
+               fragments["pre_main"] = tests[testNdx].code;
+               createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opUndefTests.get());
+       }
+       fragments.clear();
+
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %f32\n"
+               "%zero = OpFMul %f32 %undef %c_f32_0\n"
+               "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "%b = OpFAdd %f32 %a %zero\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %b %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("float32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %i32\n"
+               "%zero = OpIMul %i32 %undef %c_i32_0\n"
+               "%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("sint32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %u32\n"
+               "%zero = OpIMul %u32 %undef %c_i32_0\n"
+               "%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("uint32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %v4f32\n"
+               "%vzero = OpVectorTimesScalar %v4f32 %undef %c_f32_0\n"
+               "%zero_0 = OpVectorExtractDynamic %f32 %vzero %c_i32_0\n"
+               "%zero_1 = OpVectorExtractDynamic %f32 %vzero %c_i32_1\n"
+               "%zero_2 = OpVectorExtractDynamic %f32 %vzero %c_i32_2\n"
+               "%zero_3 = OpVectorExtractDynamic %f32 %vzero %c_i32_3\n"
+               "%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
+               "%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
+               "%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
+               "%sum_0 = OpFAdd %f32 %param1_0 %zero_0\n"
+               "%sum_1 = OpFAdd %f32 %param1_1 %zero_1\n"
+               "%sum_2 = OpFAdd %f32 %param1_2 %zero_2\n"
+               "%sum_3 = OpFAdd %f32 %param1_3 %zero_3\n"
+               "%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
+               "%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
+               "%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("vec4float32", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+       fragments["pre_main"] =
+               "%v2f32 = OpTypeVector %f32 2\n"
+               "%m2x2f32 = OpTypeMatrix %v2f32 2\n";
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%undef = OpUndef %m2x2f32\n"
+               "%mzero = OpMatrixTimesScalar %m2x2f32 %undef %c_f32_0\n"
+               "%zero_0 = OpCompositeExtract %f32 %mzero 0 0\n"
+               "%zero_1 = OpCompositeExtract %f32 %mzero 0 1\n"
+               "%zero_2 = OpCompositeExtract %f32 %mzero 1 0\n"
+               "%zero_3 = OpCompositeExtract %f32 %mzero 1 1\n"
+               "%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
+               "%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
+               "%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
+               "%sum_0 = OpFAdd %f32 %param1_0 %zero_0\n"
+               "%sum_1 = OpFAdd %f32 %param1_1 %zero_1\n"
+               "%sum_2 = OpFAdd %f32 %param1_2 %zero_2\n"
+               "%sum_3 = OpFAdd %f32 %param1_3 %zero_3\n"
+               "%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
+               "%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
+               "%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("matrix", defaultColors, defaultColors, fragments, opUndefTests.get());
+
+       return opUndefTests.release();
+}
+
+void createOpQuantizeSingleOptionTests(tcu::TestCaseGroup* testCtx)
+{
+       const RGBA              inputColors[4]          =
+       {
+               RGBA(0,         0,              0,              255),
+               RGBA(0,         0,              255,    255),
+               RGBA(0,         255,    0,              255),
+               RGBA(0,         255,    255,    255)
+       };
+
+       const RGBA              expectedColors[4]       =
+       {
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255)
+       };
+
+       const struct SingleFP16Possibility
+       {
+               const char* name;
+               const char* constant;
+               float       valueAsFloat;
+               const char* condition;
+               // condition must evaluate to true after %test_constant = OpQuantizeToF16(%constant)
+       }                               tests[]                         =
+       {
+               {
+                       "negative",
+                       "-0x1.3p1\n",
+                       -constructNormalizedFloat(1, 0x300000),
+                       "%cond = OpFOrdEqual %bool %c %test_constant\n"
+               }, // -19
+               {
+                       "positive",
+                       "0x1.0p7\n",
+                       constructNormalizedFloat(7, 0x000000),
+                       "%cond = OpFOrdEqual %bool %c %test_constant\n"
+               },  // +128
+               // SPIR-V requires that OpQuantizeToF16 flushes
+               // any numbers that would end up denormalized in F16 to zero.
+               {
+                       "denorm",
+                       "0x0.0006p-126\n",
+                       std::ldexp(1.5f, -140),
+                       "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+               },  // denorm
+               {
+                       "negative_denorm",
+                       "-0x0.0006p-126\n",
+                       -std::ldexp(1.5f, -140),
+                       "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+               }, // -denorm
+               {
+                       "too_small",
+                       "0x1.0p-16\n",
+                       std::ldexp(1.0f, -16),
+                       "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+               },      // too small negative
+               {
+                       "negative_too_small",
+                       "-0x1.0p-32\n",
+                       -std::ldexp(1.0f, -32),
+                       "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+               },     // too small positive
+               {
+                       "negative_inf",
+                       "-0x1.0p128\n",
+                       -std::ldexp(1.0f, 128),
+                       "%cond = OpFOrdEqual %bool %c %c_f32_0\n"
+
+                       "%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
+                       "%inf = OpIsInf %bool %c\n"
+                       "%cond = OpLogicalAnd %bool %gz %inf\n"
+               },     // -inf to -inf
+               {
+                       "inf",
+                       "0x1.0p128\n",
+                       std::ldexp(1.0f, 128),
+
+                       "%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
+                       "%inf = OpIsInf %bool %c\n"
+                       "%cond = OpLogicalAnd %bool %gz %inf\n"
+               },     // +inf to +inf
+               {
+                       "round_to_negative_inf",
+                       "-0x1.0p32\n",
+                       -std::ldexp(1.0f, 32),
+
+                       "%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
+                       "%inf = OpIsInf %bool %c\n"
+                       "%comp = OpLogicalAnd %bool %gz %inf\n"
+               },     // round to -inf
+               {
+                       "round_to_inf",
+                       "0x1.0p16\n",
+                       std::ldexp(1.0f, 16),
+
+                       "%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
+                       "%inf = OpIsInf %bool %c\n"
+                       "%cond = OpLogicalAnd %bool %gz %inf\n"
+               },     // round to +inf
+               {
+                       "nan",
+                       "0x1.1p128\n",
+                       std::numeric_limits<float>::quiet_NaN(),
+
+                       "%nan = OpIsNan %bool %c\n"
+                       "%as_int = OpBitcast %i32 %c\n"
+                       "%positive = OpSGreaterThan %bool %as_int %c_i32_0\n"
+                       "%cond = OpLogicalAnd %bool %nan %positive\n"
+               }, // nan
+               {
+                       "negative_nan",
+                       "-0x1.0001p128\n",
+                       std::numeric_limits<float>::quiet_NaN(),
+
+                       "%nan = OpIsNan %bool %c\n"
+                       "%as_int = OpBitcast %i32 %c\n"
+                       "%negative = OpSLessThan %bool %as_int %c_i32_0\n"
+                       "%cond = OpLogicalAnd %bool %nan %negative\n"
+               } // -nan
+       };
+       const char*             constants                       =
+               "%test_constant = OpConstant %f32\n";
+
+       StringTemplate  function                        (
+               "%test_code     = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1        = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%a             = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "%b             = OpFAdd %f32 %test_constant %a\n"
+               "%c             = OpQuantizeToF16 %f32 %b\n"
+               "${condition}\n"
+               "%retval        = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+               "                 OpReturnValue %retval\n"
+       );
+
+       const char*             specDecorations         = "OpDecorate %test_constant SpecId 0\n";
+       const char*             specConstants           =
+                       "%test_constant = OpSpecConstant %f32 0.\n"
+                       "%c             = OpSpecConstantOp %f32 QuantizeToF16 %test_constant\n";
+
+    StringTemplate     specConstantFunction(
+               "%test_code     = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1        = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "${condition}\n"
+               "%retval        = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+               "                 OpReturnValue %retval\n"
+       );
+
+       for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
+       {
+               map<string, string>                                                             codeSpecialization;
+               map<string, string>                                                             fragments;
+               codeSpecialization["condition"]                                 = tests[idx].condition;
+               fragments["testfun"]                                                    = function.specialize(codeSpecialization);
+               fragments["pre_main"]                                                   = string(constants) + tests[idx].constant + "\n";
+               createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
+       }
+
+       for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
+       {
+               map<string, string>                                                             codeSpecialization;
+               map<string, string>                                                             fragments;
+               vector<deInt32>                                                                 passConstants;
+               deInt32                                                                                 specConstant;
+
+               codeSpecialization["condition"]                                 = tests[idx].condition;
+               fragments["testfun"]                                                    = specConstantFunction.specialize(codeSpecialization);
+               fragments["decoration"]                                                 = specDecorations;
+               fragments["pre_main"]                                                   = specConstants;
+
+               memcpy(&specConstant, &tests[idx].valueAsFloat, sizeof(float));
+               passConstants.push_back(specConstant);
+
+               createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
+       }
+}
+
+void createOpQuantizeTwoPossibilityTests(tcu::TestCaseGroup* testCtx)
+{
+       RGBA inputColors[4] =  {
+               RGBA(0,         0,              0,              255),
+               RGBA(0,         0,              255,    255),
+               RGBA(0,         255,    0,              255),
+               RGBA(0,         255,    255,    255)
+       };
+
+       RGBA expectedColors[4] =
+       {
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255),
+               RGBA(255,        0,              0,              255)
+       };
+
+       struct DualFP16Possibility
+       {
+               const char* name;
+               const char* input;
+               float           inputAsFloat;
+               const char* possibleOutput1;
+               const char* possibleOutput2;
+       } tests[] = {
+               {
+                       "positive_round_up_or_round_down",
+                       "0x1.3003p8",
+                       constructNormalizedFloat(8, 0x300300),
+                       "0x1.304p8",
+                       "0x1.3p8"
+               },
+               {
+                       "negative_round_up_or_round_down",
+                       "-0x1.6008p-7",
+                       -constructNormalizedFloat(8, 0x600800),
+                       "-0x1.6p-7",
+                       "-0x1.604p-7"
+               },
+               {
+                       "carry_bit",
+                       "0x1.01ep2",
+                       constructNormalizedFloat(8, 0x01e000),
+                       "0x1.01cp2",
+                       "0x1.02p2"
+               },
+               {
+                       "carry_to_exponent",
+                       "0x1.feep1",
+                       constructNormalizedFloat(8, 0xfee000),
+                       "0x1.ffcp1",
+                       "0x1.0p2"
+               },
+       };
+       StringTemplate constants (
+               "%input_const = OpConstant %f32 ${input}\n"
+               "%possible_solution1 = OpConstant %f32 ${output1}\n"
+               "%possible_solution2 = OpConstant %f32 ${output2}\n"
+               );
+
+       StringTemplate specConstants (
+               "%input_const = OpSpecConstant %f32 0.\n"
+               "%possible_solution1 = OpConstant %f32 ${output1}\n"
+               "%possible_solution2 = OpConstant %f32 ${output2}\n"
+       );
+
+       const char* specDecorations = "OpDecorate %input_const  SpecId 0\n";
+
+       const char* function  =
+               "%test_code     = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1        = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "%a             = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               // For the purposes of this test we assume that 0.f will always get
+               // faithfully passed through the pipeline stages.
+               "%b             = OpFAdd %f32 %test_constant %a\n"
+               "%c             = OpQuantizeToF16 %f32 %b\n"
+               "%eq_1          = OpFOrdEqual %bool %c %possible_solution1\n"
+               "%eq_2          = OpFOrdEqual %bool %c %possible_solution2\n"
+               "%cond          = OpLogicalOr %bool %eq_1 %eq_2\n"
+               "%retval        = OpSelect %v4f32 %cond %c_v4f32_1_0_0_1 %param1"
+               "                 OpReturnValue %retval\n";
+
+       for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
+               map<string, string>                                                                     fragments;
+               map<string, string>                                                                     constantSpecialization;
+
+               constantSpecialization["input"]                                         = tests[idx].input;
+               constantSpecialization["output1"]                                       = tests[idx].possibleOutput1;
+               constantSpecialization["output2"]                                       = tests[idx].possibleOutput2;
+               fragments["testfun"]                                                            = function;
+               fragments["pre_main"]                                                           = constants.specialize(constantSpecialization);
+               createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
+       }
+
+       for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
+               map<string, string>                                                                     fragments;
+               map<string, string>                                                                     constantSpecialization;
+               vector<deInt32>                                                                         passConstants;
+               deInt32                                                                                         specConstant;
+
+               constantSpecialization["output1"]                                       = tests[idx].possibleOutput1;
+               constantSpecialization["output2"]                                       = tests[idx].possibleOutput2;
+               fragments["testfun"]                                                            = function;
+               fragments["decoration"]                                                         = specDecorations;
+               fragments["pre_main"]                                                           = specConstants.specialize(constantSpecialization);
+
+               memcpy(&specConstant, &tests[idx].inputAsFloat, sizeof(float));
+               passConstants.push_back(specConstant);
+
+               createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
+       }
+}
+
+tcu::TestCaseGroup* createOpQuantizeTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> opQuantizeTests (new tcu::TestCaseGroup(testCtx, "opquantize", "Test OpQuantizeToF16"));
+       createOpQuantizeSingleOptionTests(opQuantizeTests.get());
+       createOpQuantizeTwoPossibilityTests(opQuantizeTests.get());
+       return opQuantizeTests.release();
+}
+
+struct ShaderPermutation
+{
+       deUint8 vertexPermutation;
+       deUint8 geometryPermutation;
+       deUint8 tesscPermutation;
+       deUint8 tessePermutation;
+       deUint8 fragmentPermutation;
+};
+
+ShaderPermutation getShaderPermutation(deUint8 inputValue)
+{
+       ShaderPermutation       permutation =
+       {
+               static_cast<deUint8>(inputValue & 0x10? 1u: 0u),
+               static_cast<deUint8>(inputValue & 0x08? 1u: 0u),
+               static_cast<deUint8>(inputValue & 0x04? 1u: 0u),
+               static_cast<deUint8>(inputValue & 0x02? 1u: 0u),
+               static_cast<deUint8>(inputValue & 0x01? 1u: 0u)
+       };
+       return permutation;
+}
+
+tcu::TestCaseGroup* createModuleTests(tcu::TestContext& testCtx)
+{
+       RGBA                                                            defaultColors[4];
+       RGBA                                                            invertedColors[4];
+       de::MovePtr<tcu::TestCaseGroup>         moduleTests                     (new tcu::TestCaseGroup(testCtx, "module", "Multiple entry points into shaders"));
+
+       const ShaderElement                                     combinedPipeline[]      =
+       {
+               ShaderElement("module", "main", VK_SHADER_STAGE_VERTEX_BIT),
+               ShaderElement("module", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
+               ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+               ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+               ShaderElement("module", "main", VK_SHADER_STAGE_FRAGMENT_BIT)
+       };
+
+       getDefaultColors(defaultColors);
+       getInvertedDefaultColors(invertedColors);
+       addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), "same-module", "", createCombinedModule, runAndVerifyDefaultPipeline, createInstanceContext(combinedPipeline, map<string, string>()));
+
+       const char* numbers[] =
+       {
+               "1", "2"
+       };
+
+       for (deInt8 idx = 0; idx < 32; ++idx)
+       {
+               ShaderPermutation                       permutation             = getShaderPermutation(idx);
+               string                                          name                    = string("vert") + numbers[permutation.vertexPermutation] + "-geom" + numbers[permutation.geometryPermutation] + "-tessc" + numbers[permutation.tesscPermutation] + "-tesse" + numbers[permutation.tessePermutation] + "-frag" + numbers[permutation.fragmentPermutation];
+               const ShaderElement                     pipeline[]              =
+               {
+                       ShaderElement("vert",   string("vert") +        numbers[permutation.vertexPermutation],         VK_SHADER_STAGE_VERTEX_BIT),
+                       ShaderElement("geom",   string("geom") +        numbers[permutation.geometryPermutation],       VK_SHADER_STAGE_GEOMETRY_BIT),
+                       ShaderElement("tessc",  string("tessc") +       numbers[permutation.tesscPermutation],          VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+                       ShaderElement("tesse",  string("tesse") +       numbers[permutation.tessePermutation],          VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+                       ShaderElement("frag",   string("frag") +        numbers[permutation.fragmentPermutation],       VK_SHADER_STAGE_FRAGMENT_BIT)
+               };
+
+               // If there are an even number of swaps, then it should be no-op.
+               // If there are an odd number, the color should be flipped.
+               if ((permutation.vertexPermutation + permutation.geometryPermutation + permutation.tesscPermutation + permutation.tessePermutation + permutation.fragmentPermutation) % 2 == 0)
+               {
+                       addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, defaultColors, map<string, string>()));
+               }
+               else
+               {
+                       addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, invertedColors, map<string, string>()));
+               }
+       }
+       return moduleTests.release();
+}
+
+tcu::TestCaseGroup* createLoopTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "loop", "Looping control flow"));
+       RGBA defaultColors[4];
+       getDefaultColors(defaultColors);
+       map<string, string> fragments;
+
+       // A loop with a single block. The Continue Target is the loop block
+       // itself. In SPIR-V terms, the "loop construct" contains no blocks at all
+       // -- the "continue construct" forms the entire loop.
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+
+               "%entry = OpLabel\n"
+               "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "OpBranch %loop\n"
+
+               ";adds and subtracts 1.0 to %val in alternate iterations\n"
+               "%loop = OpLabel\n"
+               "%count = OpPhi %i32 %c_i32_4 %entry %count__ %loop\n"
+               "%delta = OpPhi %f32 %c_f32_1 %entry %minus_delta %loop\n"
+               "%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
+               "%val = OpFAdd %f32 %val1 %delta\n"
+               "%minus_delta = OpFSub %f32 %c_f32_0 %delta\n"
+               "%count__ = OpISub %i32 %count %c_i32_1\n"
+               "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+               "OpLoopMerge %exit %loop None\n"
+               "OpBranchConditional %again %loop %exit\n"
+
+               "%exit = OpLabel\n"
+               "%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
+               "OpReturnValue %result\n"
+
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("single-block", defaultColors, defaultColors, fragments, testGroup.get());
+
+       fragments["pre_main"] = "%c_f32_neg1 = OpConstant %f32 -1.0\n";
+
+       // Body comprised of multiple basic blocks.
+       const StringTemplate multiBlock(
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+
+               "%entry = OpLabel\n"
+               "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "OpBranch %loop\n"
+
+               ";adds and subtracts 1.0 to %val in alternate iterations\n"
+               "%loop = OpLabel\n"
+               "%count = OpPhi %i32 %c_i32_4 %entry %count__ %gather\n"
+               "%delta = OpPhi %f32 %c_f32_1 %entry %delta_next %gather\n"
+               "%val1 = OpPhi %f32 %val0 %entry %val %gather\n"
+               // There are several possibilities for the Continue Target below.  Each
+               // will be specialized into a separate test case.
+               "OpLoopMerge %exit ${continue_target} None\n"
+               "OpBranch %if\n"
+
+               "%if = OpLabel\n"
+               ";delta_next = (delta > 0) ? -1 : 1;\n"
+               "%gt0 = OpFOrdGreaterThan %bool %delta %c_f32_0\n"
+               "OpSelectionMerge %gather DontFlatten\n"
+               "OpBranchConditional %gt0 %even %odd ;tells us if %count is even or odd\n"
+
+               "%odd = OpLabel\n"
+               "OpBranch %gather\n"
+
+               "%even = OpLabel\n"
+               "OpBranch %gather\n"
+
+               "%gather = OpLabel\n"
+               "%delta_next = OpPhi %f32 %c_f32_neg1 %even %c_f32_1 %odd\n"
+               "%val = OpFAdd %f32 %val1 %delta\n"
+               "%count__ = OpISub %i32 %count %c_i32_1\n"
+               "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+               "OpBranchConditional %again %loop %exit\n"
+
+               "%exit = OpLabel\n"
+               "%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
+               "OpReturnValue %result\n"
+
+               "OpFunctionEnd\n");
+
+       map<string, string> continue_target;
+
+       // The Continue Target is the loop block itself.
+       continue_target["continue_target"] = "%loop";
+       fragments["testfun"] = multiBlock.specialize(continue_target);
+       createTestsForAllStages("multi-block-continue-construct", defaultColors, defaultColors, fragments, testGroup.get());
+
+       // The Continue Target is at the end of the loop.
+       continue_target["continue_target"] = "%gather";
+       fragments["testfun"] = multiBlock.specialize(continue_target);
+       createTestsForAllStages("multi-block-loop-construct", defaultColors, defaultColors, fragments, testGroup.get());
+
+       // \todo [2015-12-14 dekimir] More cases:
+       // - continue
+       // - early exit
+
+       return testGroup.release();
+}
+
+// Adds a new test to group using custom fragments for the tessellation-control
+// stage and passthrough fragments for all other stages.  Uses default colors
+// for input and expected output.
+void addTessCtrlTest(tcu::TestCaseGroup* group, const char* name, const map<string, string>& fragments)
+{
+       RGBA defaultColors[4];
+       getDefaultColors(defaultColors);
+       const ShaderElement pipelineStages[] =
+       {
+               ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
+               ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
+               ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
+               ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
+               ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
+       };
+
+       addFunctionCaseWithPrograms<InstanceContext>(group, name, "", addShaderCodeCustomTessControl,
+                                                                                                runAndVerifyDefaultPipeline, createInstanceContext(
+                                                                                                        pipelineStages, defaultColors, defaultColors, fragments, StageToSpecConstantMap()));
+}
+
+// A collection of tests putting OpControlBarrier in places GLSL forbids but SPIR-V allows.
+tcu::TestCaseGroup* createBarrierTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "barrier", "OpControlBarrier"));
+       map<string, string> fragments;
+
+       // A barrier inside a function body.
+       fragments["pre_main"] =
+               "%Workgroup = OpConstant %i32 2\n"
+               "%SequentiallyConsistent = OpConstant %i32 0x10\n";
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "OpReturnValue %param1\n"
+               "OpFunctionEnd\n";
+       addTessCtrlTest(testGroup.get(), "in-function", fragments);
+
+       // Common setup code for the following tests.
+       fragments["pre_main"] =
+               "%Workgroup = OpConstant %i32 2\n"
+               "%SequentiallyConsistent = OpConstant %i32 0x10\n"
+               "%c_f32_5 = OpConstant %f32 5.\n";
+       const string setupPercentZero =  // Begins %test_code function with code that sets %zero to 0u but cannot be optimized away.
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%entry = OpLabel\n"
+               ";param1 components are between 0 and 1, so dot product is 4 or less\n"
+               "%dot = OpDot %f32 %param1 %param1\n"
+               "%div = OpFDiv %f32 %dot %c_f32_5\n"
+               "%zero = OpConvertFToU %u32 %div\n";
+
+       // Barriers inside OpSwitch branches.
+       fragments["testfun"] =
+               setupPercentZero +
+               "OpSelectionMerge %switch_exit None\n"
+               "OpSwitch %zero %switch_default 0 %case0 1 %case1 ;should always go to %case0\n"
+
+               "%case1 = OpLabel\n"
+               ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "%wrong_branch_alert1 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+               "OpBranch %switch_exit\n"
+
+               "%switch_default = OpLabel\n"
+               "%wrong_branch_alert2 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+               ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "OpBranch %switch_exit\n"
+
+               "%case0 = OpLabel\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "OpBranch %switch_exit\n"
+
+               "%switch_exit = OpLabel\n"
+               "%ret = OpPhi %v4f32 %param1 %case0 %wrong_branch_alert1 %case1 %wrong_branch_alert2 %switch_default\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n";
+       addTessCtrlTest(testGroup.get(), "in-switch", fragments);
+
+       // Barriers inside if-then-else.
+       fragments["testfun"] =
+               setupPercentZero +
+               "%eq0 = OpIEqual %bool %zero %c_u32_0\n"
+               "OpSelectionMerge %exit DontFlatten\n"
+               "OpBranchConditional %eq0 %then %else\n"
+
+               "%else = OpLabel\n"
+               ";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "%wrong_branch_alert = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
+               "OpBranch %exit\n"
+
+               "%then = OpLabel\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "OpBranch %exit\n"
+
+               "%exit = OpLabel\n"
+               "%ret = OpPhi %v4f32 %param1 %then %wrong_branch_alert %else\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n";
+       addTessCtrlTest(testGroup.get(), "in-if", fragments);
+
+       // A barrier after control-flow reconvergence, tempting the compiler to attempt something like this:
+       // http://lists.llvm.org/pipermail/llvm-dev/2009-October/026317.html.
+       fragments["testfun"] =
+               setupPercentZero +
+               "%thread_id = OpLoad %i32 %gl_InvocationID\n"
+               "%thread0 = OpIEqual %bool %thread_id %c_i32_0\n"
+               "OpSelectionMerge %exit DontFlatten\n"
+               "OpBranchConditional %thread0 %then %else\n"
+
+               "%else = OpLabel\n"
+               "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "OpBranch %exit\n"
+
+               "%then = OpLabel\n"
+               "%val1 = OpVectorExtractDynamic %f32 %param1 %zero\n"
+               "OpBranch %exit\n"
+
+               "%exit = OpLabel\n"
+               "%val = OpPhi %f32 %val0 %else %val1 %then\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %val %zero\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n";
+       addTessCtrlTest(testGroup.get(), "after-divergent-if", fragments);
+
+       // A barrier inside a loop.
+       fragments["pre_main"] =
+               "%Workgroup = OpConstant %i32 2\n"
+               "%SequentiallyConsistent = OpConstant %i32 0x10\n"
+               "%c_f32_10 = OpConstant %f32 10.\n";
+       fragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%entry = OpLabel\n"
+               "%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "OpBranch %loop\n"
+
+               ";adds 1, 2, 3, and 4 to %val0\n"
+               "%loop = OpLabel\n"
+               "%count = OpPhi %i32 %c_i32_4 %entry %count__ %latch\n"
+               "%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
+               "OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
+               "%fcount = OpConvertSToF %f32 %count\n"
+               "%val = OpFAdd %f32 %val1 %fcount\n"
+               "%count__ = OpISub %i32 %count %c_i32_1\n"
+               "%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
+               "OpLoopMerge %exit %loop None\n"
+               "OpBranchConditional %again %loop %exit\n"
+
+               "%exit = OpLabel\n"
+               "%same = OpFSub %f32 %val %c_f32_10\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %same %c_i32_0\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n";
+       addTessCtrlTest(testGroup.get(), "in-loop", fragments);
+
+       return testGroup.release();
+}
+
+tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> instructionTests        (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
+       de::MovePtr<tcu::TestCaseGroup> computeTests            (new tcu::TestCaseGroup(testCtx, "compute", "Compute Instructions with special opcodes/operands"));
+       de::MovePtr<tcu::TestCaseGroup> graphicsTests           (new tcu::TestCaseGroup(testCtx, "graphics", "Graphics Instructions with special opcodes/operands"));
+
+       computeTests->addChild(createOpNopGroup(testCtx));
+       computeTests->addChild(createOpLineGroup(testCtx));
+       computeTests->addChild(createOpNoLineGroup(testCtx));
+       computeTests->addChild(createOpConstantNullGroup(testCtx));
+       computeTests->addChild(createOpConstantCompositeGroup(testCtx));
+       computeTests->addChild(createOpConstantUsageGroup(testCtx));
+       computeTests->addChild(createSpecConstantGroup(testCtx));
+       computeTests->addChild(createOpSourceGroup(testCtx));
+       computeTests->addChild(createOpSourceExtensionGroup(testCtx));
+       computeTests->addChild(createDecorationGroupGroup(testCtx));
+       computeTests->addChild(createOpPhiGroup(testCtx));
+       computeTests->addChild(createLoopControlGroup(testCtx));
+       computeTests->addChild(createFunctionControlGroup(testCtx));
+       computeTests->addChild(createSelectionControlGroup(testCtx));
+       computeTests->addChild(createBlockOrderGroup(testCtx));
+       computeTests->addChild(createMultipleShaderGroup(testCtx));
+       computeTests->addChild(createMemoryAccessGroup(testCtx));
+       computeTests->addChild(createOpCopyMemoryGroup(testCtx));
+       computeTests->addChild(createOpCopyObjectGroup(testCtx));
+       computeTests->addChild(createNoContractionGroup(testCtx));
+       computeTests->addChild(createOpUndefGroup(testCtx));
+       computeTests->addChild(createOpUnreachableGroup(testCtx));
+       computeTests ->addChild(createOpQuantizeToF16Group(testCtx));
+
+       RGBA defaultColors[4];
+       getDefaultColors(defaultColors);
+
+       de::MovePtr<tcu::TestCaseGroup> opnopTests (new tcu::TestCaseGroup(testCtx, "opnop", "Test OpNop"));
+       map<string, string> opNopFragments;
+       opNopFragments["testfun"] =
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpNop\n"
+               "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
+               "%b = OpFAdd %f32 %a %a\n"
+               "OpNop\n"
+               "%c = OpFSub %f32 %b %a\n"
+               "%ret = OpVectorInsertDynamic %v4f32 %param1 %c %c_i32_0\n"
+               "OpNop\n"
+               "OpNop\n"
+               "OpReturnValue %ret\n"
+               "OpFunctionEnd\n"
+               ;
+       createTestsForAllStages("opnop", defaultColors, defaultColors, opNopFragments, opnopTests.get());
+
+
+       graphicsTests->addChild(opnopTests.release());
+       graphicsTests->addChild(createOpSourceTests(testCtx));
+       graphicsTests->addChild(createOpSourceContinuedTests(testCtx));
+       graphicsTests->addChild(createOpLineTests(testCtx));
+       graphicsTests->addChild(createOpNoLineTests(testCtx));
+       graphicsTests->addChild(createOpConstantNullTests(testCtx));
+       graphicsTests->addChild(createOpConstantCompositeTests(testCtx));
+       graphicsTests->addChild(createMemoryAccessTests(testCtx));
+       graphicsTests->addChild(createOpUndefTests(testCtx));
+       graphicsTests->addChild(createSelectionBlockOrderTests(testCtx));
+       graphicsTests->addChild(createModuleTests(testCtx));
+       graphicsTests->addChild(createSwitchBlockOrderTests(testCtx));
+       graphicsTests->addChild(createOpPhiTests(testCtx));
+       graphicsTests->addChild(createNoContractionTests(testCtx));
+       graphicsTests->addChild(createOpQuantizeTests(testCtx));
+       graphicsTests->addChild(createLoopTests(testCtx));
+       graphicsTests->addChild(createSpecConstantTests(testCtx));
+       graphicsTests->addChild(createSpecConstantOpQuantizeToF16Group(testCtx));
+       graphicsTests->addChild(createBarrierTests(testCtx));
+       graphicsTests->addChild(createDecorationGroupTests(testCtx));
+
+       instructionTests->addChild(computeTests.release());
+       instructionTests->addChild(graphicsTests.release());
+
        return instructionTests.release();
 }
 
diff --git a/external/vulkancts/modules/vulkan/vktInfo.cpp b/external/vulkancts/modules/vulkan/vktInfo.cpp
deleted file mode 100644 (file)
index 551b4dc..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*-------------------------------------------------------------------------
- * Vulkan Conformance Tests
- * ------------------------
- *
- * Copyright (c) 2015 Google Inc.
- *
- * 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 Platform information tests
- *//*--------------------------------------------------------------------*/
-
-#include "vktInfo.hpp"
-
-#include "vktTestCaseUtil.hpp"
-
-#include "vkPlatform.hpp"
-#include "vkStrUtil.hpp"
-#include "vkRef.hpp"
-#include "vkDeviceUtil.hpp"
-#include "vkQueryUtil.hpp"
-
-#include "tcuTestLog.hpp"
-#include "tcuFormatUtil.hpp"
-
-#include "deUniquePtr.hpp"
-#include "deMemory.h"
-
-namespace vkt
-{
-namespace
-{
-
-using namespace vk;
-using std::vector;
-using std::string;
-using tcu::TestLog;
-using tcu::ScopedLogSection;
-
-tcu::TestStatus enumeratePhysicalDevices (Context& context)
-{
-       TestLog&                                                log             = context.getTestContext().getLog();
-       const vector<VkPhysicalDevice>  devices = enumeratePhysicalDevices(context.getInstanceInterface(), context.getInstance());
-
-       log << TestLog::Integer("NumDevices", "Number of devices", "", QP_KEY_TAG_NONE, deInt64(devices.size()));
-
-       for (size_t ndx = 0; ndx < devices.size(); ndx++)
-               log << TestLog::Message << ndx << ": " << devices[ndx] << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Enumerating devices succeeded");
-}
-
-tcu::TestStatus enumerateInstanceLayers (Context& context)
-{
-       TestLog&                                                log                     = context.getTestContext().getLog();
-       const vector<VkLayerProperties> properties      = enumerateInstanceLayerProperties(context.getPlatformInterface());
-
-       for (size_t ndx = 0; ndx < properties.size(); ndx++)
-               log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Enumerating layers succeeded");
-}
-
-tcu::TestStatus enumerateInstanceExtensions (Context& context)
-{
-       TestLog&        log             = context.getTestContext().getLog();
-
-       {
-               const ScopedLogSection                          section         (log, "Global", "Global Extensions");
-               const vector<VkExtensionProperties>     properties      = enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL);
-
-               for (size_t ndx = 0; ndx < properties.size(); ndx++)
-                       log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-       }
-
-       {
-               const vector<VkLayerProperties> layers  = enumerateInstanceLayerProperties(context.getPlatformInterface());
-
-               for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
-               {
-                       const ScopedLogSection                          section         (log, layer->layerName, string("Layer: ") + layer->layerName);
-                       const vector<VkExtensionProperties>     properties      = enumerateInstanceExtensionProperties(context.getPlatformInterface(), layer->layerName);
-
-                       for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
-                               log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
-               }
-       }
-
-       return tcu::TestStatus::pass("Enumerating extensions succeeded");
-}
-
-tcu::TestStatus enumerateDeviceLayers (Context& context)
-{
-       TestLog&                                                log                     = context.getTestContext().getLog();
-       const vector<VkLayerProperties> properties      = vk::enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
-       for (size_t ndx = 0; ndx < properties.size(); ndx++)
-               log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Enumerating layers succeeded");
-}
-
-tcu::TestStatus enumerateDeviceExtensions (Context& context)
-{
-       TestLog&        log             = context.getTestContext().getLog();
-
-       {
-               const ScopedLogSection                          section         (log, "Global", "Global Extensions");
-               const vector<VkExtensionProperties>     properties      = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), DE_NULL);
-
-               for (size_t ndx = 0; ndx < properties.size(); ndx++)
-                       log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
-       }
-
-       {
-               const vector<VkLayerProperties> layers  = enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
-               for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
-               {
-                       const ScopedLogSection                          section         (log, layer->layerName, string("Layer: ") + layer->layerName);
-                       const vector<VkExtensionProperties>     properties      = enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), layer->layerName);
-
-                       for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
-                               log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
-               }
-       }
-
-       return tcu::TestStatus::pass("Enumerating extensions succeeded");
-}
-
-tcu::TestStatus deviceFeatures (Context& context)
-{
-       TestLog&                                                log                     = context.getTestContext().getLog();
-       VkPhysicalDeviceFeatures                features;
-
-       deMemset(&features, 0, sizeof(features));
-
-       context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
-
-       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
-               << TestLog::Message << features << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Query succeeded");
-}
-
-tcu::TestStatus deviceProperties (Context& context)
-{
-       TestLog&                                                log                     = context.getTestContext().getLog();
-       VkPhysicalDeviceProperties              props;
-
-       deMemset(&props, 0, sizeof(props));
-
-       context.getInstanceInterface().getPhysicalDeviceProperties(context.getPhysicalDevice(), &props);
-
-       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
-               << TestLog::Message << props << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Query succeeded");
-}
-
-tcu::TestStatus deviceQueueFamilyProperties (Context& context)
-{
-       TestLog&                                                                log                                     = context.getTestContext().getLog();
-       const vector<VkQueueFamilyProperties>   queueProperties         = getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
-
-       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
-
-       for (size_t queueNdx = 0; queueNdx < queueProperties.size(); queueNdx++)
-               log << TestLog::Message << queueNdx << ": " << queueProperties[queueNdx] << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Querying queue properties succeeded");
-}
-
-tcu::TestStatus deviceMemoryProperties (Context& context)
-{
-       TestLog&        log             = context.getTestContext().getLog();
-
-       log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
-
-       log << TestLog::Message
-               << getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())
-               << TestLog::EndMessage;
-
-       return tcu::TestStatus::pass("Querying memory properties succeeded");
-}
-
-} // anonymous
-
-tcu::TestCaseGroup* createInfoTests (tcu::TestContext& testCtx)
-{
-       de::MovePtr<tcu::TestCaseGroup> infoTests       (new tcu::TestCaseGroup(testCtx, "info", "Platform Information Tests"));
-
-       {
-               de::MovePtr<tcu::TestCaseGroup> instanceInfoTests       (new tcu::TestCaseGroup(testCtx, "instance", "Instance Information Tests"));
-
-               addFunctionCase(instanceInfoTests.get(), "physical_devices",            "Physical devices",                     enumeratePhysicalDevices);
-               addFunctionCase(instanceInfoTests.get(), "layers",                                      "Layers",                                       enumerateInstanceLayers);
-               addFunctionCase(instanceInfoTests.get(), "extensions",                          "Extensions",                           enumerateInstanceExtensions);
-
-               infoTests->addChild(instanceInfoTests.release());
-       }
-
-       {
-               de::MovePtr<tcu::TestCaseGroup> deviceInfoTests (new tcu::TestCaseGroup(testCtx, "device", "Device Information Tests"));
-
-               addFunctionCase(deviceInfoTests.get(), "features",                                      "Device Features",                      deviceFeatures);
-               addFunctionCase(deviceInfoTests.get(), "properties",                            "Device Properties",            deviceProperties);
-               addFunctionCase(deviceInfoTests.get(), "queue_family_properties",       "Queue family properties",      deviceQueueFamilyProperties);
-               addFunctionCase(deviceInfoTests.get(), "memory_properties",                     "Memory properties",            deviceMemoryProperties);
-               addFunctionCase(deviceInfoTests.get(), "layers",                                        "Layers",                                       enumerateDeviceLayers);
-               addFunctionCase(deviceInfoTests.get(), "extensions",                            "Extensions",                           enumerateDeviceExtensions);
-
-               infoTests->addChild(deviceInfoTests.release());
-       }
-
-       return infoTests.release();
-}
-
-} // vkt
index 007b85d..f7f1748 100644 (file)
@@ -1186,8 +1186,8 @@ public:
 
                        if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
                        {
-                               const tcu::TextureFormat        depthFormat             = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
-                               const tcu::TextureFormat        stencilFormat   = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+                               const tcu::TextureFormat        depthFormat             = getDepthCopyFormat(attachmentInfo.getFormat());
+                               const tcu::TextureFormat        stencilFormat   = getStencilCopyFormat(attachmentInfo.getFormat());
 
                                m_bufferSize                    = size.x() * size.y() * depthFormat.getPixelSize();
                                m_secondaryBufferSize   = size.x() * size.y() * stencilFormat.getPixelSize();
@@ -1649,7 +1649,7 @@ Move<VkPipeline> createSubpassPipeline (const DeviceInterface&            vk,
                        VK_COMPARE_OP_ALWAYS,                                                                   // stencilCompareOp
                        ~0u,                                                                                                    // stencilCompareMask
                        ~0u,                                                                                                    // stencilWriteMask
-                       ~0u                                                                                                             // stencilReference
+                       STENCIL_VALUE                                                                                   // stencilReference
                },                                                                                                                      // front
                {
                        VK_STENCIL_OP_REPLACE,                                                                  // stencilFailOp
@@ -1658,7 +1658,7 @@ Move<VkPipeline> createSubpassPipeline (const DeviceInterface&            vk,
                        VK_COMPARE_OP_ALWAYS,                                                                   // stencilCompareOp
                        ~0u,                                                                                                    // stencilCompareMask
                        ~0u,                                                                                                    // stencilWriteMask
-                       ~0u                                                                                                             // stencilReference
+                       STENCIL_VALUE                                                                                   // stencilReference
                },                                                                                                                      // back
 
                -1.0f,                                                                                                          // minDepthBounds;
@@ -1925,8 +1925,8 @@ void pushImageInitializationCommands (const DeviceInterface&                                                              vk,
                        };
                        const VkImageSubresourceRange range =
                        {
-                               (VkImageAspectFlags)(hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0
-                                                                        | hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0),
+                               (VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0)
+                                                                        | (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)),
                                0,
                                1,
                                0,
@@ -2790,6 +2790,12 @@ void checkColorRenderQuad (const ConstPixelBufferAccess& result,
                                                                                                                 de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
        const BVec4                                             channelMask                     = tcu::getTextureFormatChannelMask(format);
 
+       IVec4                                           formatBitDepths = tcu::getTextureFormatBitDepth(format);
+       Vec4                                            threshold = Vec4(1.0f) / Vec4((float)(1 << formatBitDepths.x()),
+                                                                                                                               (float)(1 << formatBitDepths.y()),
+                                                                                                                               (float)(1 << formatBitDepths.z()),
+                                                                                                                               (float)(1 << formatBitDepths.w()));
+
        switch (channelClass)
        {
                case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
@@ -2811,9 +2817,9 @@ void checkColorRenderQuad (const ConstPixelBufferAccess&  result,
                                        const Vec4      resColor        (result.getPixel(x, y));
 
                                        const Vec4      minRefColor     = srgb ? tcu::linearToSRGB(valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs))
-                                                                                                        : valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
+                                                                                                        : valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs) - threshold;
                                        const Vec4      maxRefColor     = srgb ? tcu::linearToSRGB(valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs))
-                                                                                                        : valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
+                                                                                                        : valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs) + threshold;
 
                                        DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
                                        DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
@@ -3244,13 +3250,13 @@ bool logAndVerifyImages (TestLog&                                                                                       log,
 
                        if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
                        {
-                               const tcu::TextureFormat        depthFormat             = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
+                               const tcu::TextureFormat        depthFormat             = getDepthCopyFormat(attachment.getFormat());
                                const VkDeviceSize                      depthBufferSize = targetSize.x() * targetSize.y() * depthFormat.getPixelSize();
                                void* const                                     depthPtr                = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
 
-                               const tcu::TextureFormat        stencilFormat           = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+                               const tcu::TextureFormat        stencilFormat           = getStencilCopyFormat(attachment.getFormat());
                                const VkDeviceSize                      stencilBufferSize       = targetSize.x() * targetSize.y() * stencilFormat.getPixelSize();
-                               void* const                                     stencilPtr                      = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
+                               void* const                                     stencilPtr                      = attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr();
 
                                const VkMappedMemoryRange       ranges[] =
                                {
index e60d6d9..9ff6a28 100644 (file)
@@ -46,7 +46,6 @@
 
 #include "deUniquePtr.hpp"
 
-#include "vktInfo.hpp"
 #include "vktApiTests.hpp"
 #include "vktPipelineTests.hpp"
 #include "vktBindingModelTests.hpp"
@@ -304,7 +303,6 @@ tcu::TestCaseExecutor* TestPackage::createExecutor (void) const
 
 void TestPackage::init (void)
 {
-       addChild(createInfoTests                        (m_testCtx));
        addChild(api::createTests                       (m_testCtx));
        addChild(pipeline::createTests          (m_testCtx));
        addChild(BindingModel::createTests      (m_testCtx));
index 6550267..def031d 100644 (file)
@@ -218,6 +218,24 @@ DE_INLINE deBool deIsPowerOfTwo64 (deUint64 a)
 }
 
 /*--------------------------------------------------------------------*//*!
+ * \brief Check if a value is a power-of-two.
+ * \param a Input value.
+ * \return True if input is a power-of-two value, false otherwise.
+ *
+ * \note Also returns true for zero.
+ *//*--------------------------------------------------------------------*/
+DE_INLINE deBool deIsPowerOfTwoSize (size_t a)
+{
+#if (DE_PTR_SIZE == 4)
+       return deIsPowerOfTwo32(a);
+#elif (DE_PTR_SIZE == 8)
+       return deIsPowerOfTwo64(a);
+#else
+#      error "Invalid DE_PTR_SIZE"
+#endif
+}
+
+/*--------------------------------------------------------------------*//*!
  * \brief Check if an integer is aligned to given power-of-two size.
  * \param a            Input value.
  * \param align        Alignment to check for.
@@ -266,6 +284,18 @@ DE_INLINE void* deAlignPtr (void* ptr, deUintptr align)
        return (void*)((val + align - 1) & ~(align - 1));
 }
 
+/*--------------------------------------------------------------------*//*!
+ * \brief Align a size_t value to given power-of-two size.
+ * \param ptr  Input value to align.
+ * \param align        Alignment to check for (power-of-two).
+ * \return The aligned size (larger or equal to input).
+ *//*--------------------------------------------------------------------*/
+DE_INLINE size_t deAlignSize (size_t val, size_t align)
+{
+       DE_ASSERT(deIsPowerOfTwoSize(align));
+       return (val + align - 1) & ~(align - 1);
+}
+
 extern const deInt8 g_clzLUT[256];
 
 /*--------------------------------------------------------------------*//*!
index 35d2cf7..90795a0 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#define DE_ALIGNED_MALLOC_POSIX                0
+#define DE_ALIGNED_MALLOC_WIN32                1
+#define DE_ALIGNED_MALLOC_GENERIC      2
+
+#if (DE_OS == DE_OS_UNIX) || ((DE_OS == DE_OS_ANDROID) && (DE_ANDROID_API >= 21))
+#      define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_POSIX
+#      include <malloc.h>
+#elif (DE_OS == DE_OS_WIN32)
+#      define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_WIN32
+#      include <malloc.h>
+#else
+#      define DE_ALIGNED_MALLOC DE_ALIGNED_MALLOC_GENERIC
+#endif
+
 #if defined(DE_VALGRIND_BUILD)
 #      include <valgrind/valgrind.h>
 #      if defined(HAVE_VALGRIND_MEMCHECK_H)
@@ -81,24 +95,6 @@ void* deCalloc (size_t numBytes)
        return ptr;
 }
 
-void* deAlignedMalloc (size_t numBytes, deUint32 alignBytes)
-{
-       size_t          ptrSize         = sizeof(void*);
-       deUintptr       origPtr         = (deUintptr)deMalloc(numBytes + ptrSize + (size_t)alignBytes);
-
-       DE_ASSERT(deInRange32(alignBytes, 0, 256) && deIsPowerOfTwo32(alignBytes));
-
-       if (origPtr)
-       {
-               deUintptr       alignedPtr      = (deUintptr)deAlignPtr((void*)(origPtr + ptrSize), (deUintptr)alignBytes);
-               deUintptr       ptrPtr          = (alignedPtr - ptrSize);
-               *(deUintptr*)ptrPtr = origPtr;
-               return (void*)alignedPtr;
-       }
-       else
-               return DE_NULL;
-}
-
 /*--------------------------------------------------------------------*//*!
  * \brief Reallocate a chunk of memory.
  * \param ptr          Pointer to previously allocated memory block
@@ -119,16 +115,141 @@ void deFree (void* ptr)
        free(ptr);
 }
 
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+
+typedef struct AlignedAllocHeader_s
+{
+       void*   basePtr;
+       size_t  numBytes;
+} AlignedAllocHeader;
+
+DE_INLINE AlignedAllocHeader* getAlignedAllocHeader (void* ptr)
+{
+       const size_t    hdrSize         = sizeof(AlignedAllocHeader);
+       const deUintptr hdrAddr         = (deUintptr)ptr - hdrSize;
+
+       return (AlignedAllocHeader*)hdrAddr;
+}
+
+#endif
+
+void* deAlignedMalloc (size_t numBytes, size_t alignBytes)
+{
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+       /* posix_memalign() requires that alignment must be 2^N * sizeof(void*) */
+       const size_t    ptrAlignedAlign = deAlignSize(alignBytes, sizeof(void*));
+       void*                   ptr                             = DE_NULL;
+
+       DE_ASSERT(deIsPowerOfTwoSize(alignBytes) && deIsPowerOfTwoSize(ptrAlignedAlign / sizeof(void*)));
+
+       if (posix_memalign(&ptr, ptrAlignedAlign, numBytes) == 0)
+       {
+               DE_ASSERT(ptr);
+               return ptr;
+       }
+       else
+       {
+               DE_ASSERT(!ptr);
+               return DE_NULL;
+       }
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+       DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
+
+       return _aligned_malloc(numBytes, alignBytes);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+       void* const     basePtr = deMalloc(numBytes + alignBytes + sizeof(AlignedAllocHeader));
+
+       DE_ASSERT(deIsPowerOfTwoSize(alignBytes));
+
+       if (basePtr)
+       {
+               void* const                                     alignedPtr      = deAlignPtr((void*)((deUintptr)basePtr + sizeof(AlignedAllocHeader)), alignBytes);
+               AlignedAllocHeader* const       hdr                     = getAlignedAllocHeader(alignedPtr);
+
+               hdr->basePtr    = basePtr;
+               hdr->numBytes   = numBytes;
+
+               return alignedPtr;
+       }
+       else
+               return DE_NULL;
+#else
+#      error "Invalid DE_ALIGNED_MALLOC"
+#endif
+}
+
+void* deAlignedRealloc (void* ptr, size_t numBytes, size_t alignBytes)
+{
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+       return _aligned_realloc(ptr, numBytes, alignBytes);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC) || (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+       if (ptr)
+       {
+               if (numBytes > 0)
+               {
+#      if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
+                       const size_t                            oldSize = getAlignedAllocHeader(ptr)->numBytes;
+#      else /* DE_ALIGNED_MALLOC_GENERIC */
+                       const size_t                            oldSize = malloc_usable_size(ptr);
+#      endif
+
+                       DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
+
+                       if (oldSize < numBytes || oldSize > numBytes*2)
+                       {
+                               /* Create a new alloc if original is smaller, or more than twice the requested size */
+                               void* const     newPtr  = deAlignedMalloc(numBytes, alignBytes);
+
+                               if (newPtr)
+                               {
+                                       const size_t    copyBytes       = numBytes < oldSize ? numBytes : oldSize;
+
+                                       deMemcpy(newPtr, ptr, copyBytes);
+                                       deAlignedFree(ptr);
+
+                                       return newPtr;
+                               }
+                               else
+                                       return DE_NULL;
+                       }
+                       else
+                               return ptr;
+               }
+               else
+               {
+                       deAlignedFree(ptr);
+                       return DE_NULL;
+               }
+       }
+       else
+               return deAlignedMalloc(numBytes, alignBytes);
+
+#else
+#      error "Invalid DE_ALIGNED_MALLOC"
+#endif
+}
+
 void deAlignedFree (void* ptr)
 {
+#if (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_POSIX)
+       free(ptr);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_WIN32)
+       _aligned_free(ptr);
+
+#elif (DE_ALIGNED_MALLOC == DE_ALIGNED_MALLOC_GENERIC)
        if (ptr)
        {
-               size_t          ptrSize         = sizeof(void*);
-               deUintptr       ptrPtr          = (deUintptr)ptr - ptrSize;
-               deUintptr       origPtr         = *(deUintptr*)ptrPtr;
-               DE_ASSERT(ptrPtr - origPtr < 256);
-               deFree((void*)origPtr);
+               AlignedAllocHeader* const       hdr     = getAlignedAllocHeader(ptr);
+
+               deFree(hdr->basePtr);
        }
+#else
+#      error "Invalid DE_ALIGNED_MALLOC"
+#endif
 }
 
 char* deStrdup (const char* str)
@@ -147,4 +268,89 @@ char* deStrdup (const char* str)
 #endif
 }
 
+void deMemory_selfTest (void)
+{
+       static const struct
+       {
+               size_t          numBytes;
+               size_t          alignment;
+       } s_alignedAllocCases[] =
+       {
+               { 1,            1               },
+               { 1,            2               },
+               { 1,            256             },
+               { 1,            4096    },
+               { 547389,       1               },
+               { 547389,       2               },
+               { 547389,       256             },
+               { 547389,       4096    },
+               { 52532,        1<<4    },
+               { 52532,        1<<10   },
+               { 52532,        1<<16   },
+       };
+       static const struct
+       {
+               size_t          initialSize;
+               size_t          newSize;
+               size_t          alignment;
+       } s_alignedReallocCases[] =
+       {
+               { 1,            1,              1               },
+               { 1,            1,              2               },
+               { 1,            1,              256             },
+               { 1,            1,              4096    },
+               { 1,            1241,   1               },
+               { 1,            1241,   2               },
+               { 1,            1241,   256             },
+               { 1,            1241,   4096    },
+               { 547389,       234,    1               },
+               { 547389,       234,    2               },
+               { 547389,       234,    256             },
+               { 547389,       234,    4096    },
+               { 52532,        421523, 1<<4    },
+               { 52532,        421523, 1<<10   },
+               { 52532,        421523, 1<<16   },
+       };
+
+       int caseNdx;
+
+       for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedAllocCases); caseNdx++)
+       {
+               void* const             ptr             = deAlignedMalloc(s_alignedAllocCases[caseNdx].numBytes, s_alignedAllocCases[caseNdx].alignment);
+
+               DE_TEST_ASSERT(ptr);
+               DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedAllocCases[caseNdx].alignment));
+
+               deMemset(ptr, 0xaa, s_alignedAllocCases[caseNdx].numBytes);
+
+               deAlignedFree(ptr);
+       }
+
+       for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_alignedReallocCases); caseNdx++)
+       {
+               void* const             ptr             = deAlignedMalloc(s_alignedReallocCases[caseNdx].initialSize, s_alignedReallocCases[caseNdx].alignment);
+
+               DE_TEST_ASSERT(ptr);
+               DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
+
+               deMemset(ptr, 0xaa, s_alignedReallocCases[caseNdx].initialSize);
+
+               {
+                       void* const             newPtr                  = deAlignedRealloc(ptr, s_alignedReallocCases[caseNdx].newSize, s_alignedReallocCases[caseNdx].alignment);
+                       const size_t    numPreserved    = s_alignedReallocCases[caseNdx].newSize < s_alignedReallocCases[caseNdx].initialSize
+                                                                                       ? s_alignedReallocCases[caseNdx].newSize
+                                                                                       : s_alignedReallocCases[caseNdx].initialSize;
+                       size_t                  off;
+
+                       DE_TEST_ASSERT(newPtr);
+                       DE_TEST_ASSERT(deIsAlignedPtr(ptr, s_alignedReallocCases[caseNdx].alignment));
+
+                       for (off = 0; off < numPreserved; off++)
+                               DE_TEST_ASSERT(*((const deUint8*)newPtr + off) == 0xaa);
+
+                       deAlignedFree(newPtr);
+               }
+       }
+}
+
 DE_END_EXTERN_C
index 105d4d9..a5e6150 100644 (file)
@@ -37,7 +37,8 @@ void* deCalloc                (size_t numBytes);
 void*  deRealloc               (void* ptr, size_t numBytes);
 void   deFree                  (void* ptr);
 
-void*  deAlignedMalloc (size_t numBytes, deUint32 alignBytes);
+void*  deAlignedMalloc (size_t numBytes, size_t alignBytes);
+void*  deAlignedRealloc(void* ptr, size_t numBytes, size_t alignBytes);
 void   deAlignedFree   (void* ptr);
 
 char*  deStrdup                (const char* str);
@@ -76,6 +77,8 @@ DE_INLINE void* deMemmove (void* dst, const void* src, size_t numBytes)
        return memmove(dst, src, numBytes);
 }
 
+void   deMemory_selfTest       (void);
+
 DE_END_EXTERN_C
 
 #endif /* _DEMEMORY_H */
index 4994b2d..1266335 100644 (file)
@@ -5,6 +5,8 @@ if (NOT DE_DEFS)
 endif ()
 
 set(DECPP_SRCS
+       deAppendList.cpp
+       deAppendList.hpp
        deArrayBuffer.cpp
        deArrayBuffer.hpp
        deArrayUtil.cpp
diff --git a/framework/delibs/decpp/deAppendList.cpp b/framework/delibs/decpp/deAppendList.cpp
new file mode 100644 (file)
index 0000000..ed7ef74
--- /dev/null
@@ -0,0 +1,155 @@
+/*-------------------------------------------------------------------------
+ * drawElements C++ Base Library
+ * -----------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Fast ordered append-only container
+ *//*--------------------------------------------------------------------*/
+
+#include "deAppendList.hpp"
+#include "deThread.hpp"
+#include "deSpinBarrier.hpp"
+#include "deSharedPtr.hpp"
+
+#include <vector>
+#include <algorithm>
+
+namespace de
+{
+
+namespace
+{
+
+using std::vector;
+
+struct TestElem
+{
+       deUint32        threadNdx;
+       deUint32        elemNdx;
+
+       TestElem (deUint32 threadNdx_, deUint32 elemNdx_)
+               : threadNdx     (threadNdx_)
+               , elemNdx       (elemNdx_)
+       {}
+
+       TestElem (void)
+               : threadNdx     (0)
+               , elemNdx       (0)
+       {}
+};
+
+struct SharedState
+{
+       deUint32                                numElements;
+       SpinBarrier                             barrier;
+       AppendList<TestElem>    testList;
+
+       SharedState (deUint32 numThreads, deUint32 numElements_, deUint32 numElementsHint)
+               : numElements   (numElements_)
+               , barrier               (numThreads)
+               , testList              (numElementsHint)
+       {}
+};
+
+class TestThread : public Thread
+{
+public:
+       TestThread (SharedState* shared, deUint32 threadNdx)
+               : m_shared              (shared)
+               , m_threadNdx   (threadNdx)
+       {}
+
+       void run (void)
+       {
+               const deUint32  syncPerElems    = 10000;
+
+               for (deUint32 elemNdx = 0; elemNdx < m_shared->numElements; elemNdx++)
+               {
+                       if (elemNdx % syncPerElems == 0)
+                               m_shared->barrier.sync(SpinBarrier::WAIT_MODE_AUTO);
+
+                       m_shared->testList.append(TestElem(m_threadNdx, elemNdx));
+               }
+       }
+
+private:
+       SharedState* const      m_shared;
+       const deUint32          m_threadNdx;
+};
+
+typedef SharedPtr<TestThread> TestThreadSp;
+
+void runAppendListTest (deUint32 numThreads, deUint32 numElements, deUint32 numElementsHint)
+{
+       SharedState                             sharedState             (numThreads, numElements, numElementsHint);
+       vector<TestThreadSp>    threads                 (numThreads);
+
+       for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+       {
+               threads[threadNdx] = TestThreadSp(new TestThread(&sharedState, threadNdx));
+               threads[threadNdx]->start();
+       }
+
+       for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+               threads[threadNdx]->join();
+
+       DE_TEST_ASSERT(sharedState.testList.size() == (size_t)numElements*(size_t)numThreads);
+
+       {
+               vector<deUint32>        countByThread   (numThreads);
+
+               std::fill(countByThread.begin(), countByThread.end(), 0);
+
+               for (AppendList<TestElem>::const_iterator elemIter = sharedState.testList.begin();
+                        elemIter != sharedState.testList.end();
+                        ++elemIter)
+               {
+                       const TestElem& elem    = *elemIter;
+
+                       DE_TEST_ASSERT(de::inBounds(elem.threadNdx, 0u, numThreads));
+                       DE_TEST_ASSERT(countByThread[elem.threadNdx] == elem.elemNdx);
+
+                       countByThread[elem.threadNdx] += 1;
+               }
+
+               for (deUint32 threadNdx = 0; threadNdx < numThreads; ++threadNdx)
+                       DE_TEST_ASSERT(countByThread[threadNdx] == numElements);
+       }
+}
+
+} // anonymous
+
+void AppendList_selfTest (void)
+{
+       // Single-threaded
+       runAppendListTest(1, 1000, 500);
+       runAppendListTest(1, 1000, 2000);
+       runAppendListTest(1, 35, 1);
+
+       // Multi-threaded
+       runAppendListTest(2, 10000, 500);
+       runAppendListTest(2, 100, 10);
+
+       if (deGetNumAvailableLogicalCores() >= 4)
+       {
+               runAppendListTest(4, 10000, 500);
+               runAppendListTest(4, 100, 10);
+       }
+}
+
+} // de
diff --git a/framework/delibs/decpp/deAppendList.hpp b/framework/delibs/decpp/deAppendList.hpp
new file mode 100644 (file)
index 0000000..4c37767
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef _DEAPPENDLIST_HPP
+#define _DEAPPENDLIST_HPP
+/*-------------------------------------------------------------------------
+ * drawElements C++ Base Library
+ * -----------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Fast ordered append-only container
+ *//*--------------------------------------------------------------------*/
+
+#include "deDefs.hpp"
+#include "deAtomic.h"
+#include "deThread.h"
+#include "deMemory.h"
+#include "deInt32.h"
+
+namespace de
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Fast ordered append-only container
+ *
+ * AppendList provides data structure for recording ordered list of elements
+ * quickly, while still providing good sequential read access speed.
+ * It is good for example logging.
+ *
+ * AppendList allocates memory in blocks of blockSize elements. Choosing
+ * too small blockSize will affect performance.
+ *
+ * Elements can be appended from multiple threads simultaneously but if
+ * current block runs out, allocation of next block will happen in a single
+ * thread and block others from inserting further elements until completed.
+ * For that reason shared AppendList should not be used if there is a lot
+ * of contention and instead per-thread AppendList's are recommended.
+ *//*--------------------------------------------------------------------*/
+template<typename ElementType>
+class AppendList
+{
+public:
+                                                               AppendList              (size_t blockSize);
+                                                               ~AppendList             (void);
+
+       void                                            append                  (const ElementType& value);
+
+       size_t                                          size                    (void) const { return m_numElements;    }
+
+private:
+                                                               AppendList              (const AppendList<ElementType>&);
+       AppendList<ElementType>&        operator=               (const AppendList<ElementType>&);
+
+       struct Block
+       {
+               const size_t            blockNdx;
+               ElementType*            elements;
+               Block* volatile         next;
+
+               Block (size_t blockNdx_, size_t size)
+                       : blockNdx      (blockNdx_)
+                       , elements      (reinterpret_cast<ElementType*>(deAlignedMalloc(sizeof(ElementType)*size,
+                                                                                                                                               deAlign32((deUint32)alignOf<ElementType>(), (deUint32)sizeof(void*)))))
+                       , next          (DE_NULL)
+               {
+               }
+
+               ~Block (void)
+               {
+                       deAlignedFree(reinterpret_cast<void*>(elements));
+               }
+       };
+
+       const size_t                            m_blockSize;
+       volatile size_t                         m_numElements;
+       Block*                                          m_first;
+       Block* volatile                         m_last;
+
+public:
+       template<typename CompatibleType>
+       class Iterator
+       {
+       public:
+                                                                       Iterator                                                (Block* curBlock_, size_t blockSize_, size_t slotNdx_)
+                                                                                                                                               : m_curBlock    (curBlock_)
+                                                                                                                                               , m_blockSize   (blockSize_)
+                                                                                                                                               , m_slotNdx             (slotNdx_)
+               {}
+
+               bool                                            operator!=                                              (const Iterator<CompatibleType>& other) const
+               {
+                       return m_curBlock != other.m_curBlock || m_slotNdx != other.m_slotNdx;
+               }
+               bool                                            operator==                                              (const Iterator<CompatibleType>& other) const
+               {
+                       return m_curBlock == other.m_curBlock && m_slotNdx == other.m_slotNdx;
+               }
+
+               Iterator<CompatibleType>&       operator++                                              (void)
+               {
+                       ++m_slotNdx;
+
+                       if (m_slotNdx == m_blockSize)
+                       {
+                               m_slotNdx = 0;
+                               m_curBlock = m_curBlock->next;
+                       }
+
+                       return *this;
+               }
+
+               Iterator<CompatibleType>        operator++                                              (int) const
+               {
+                       Iterator<CompatibleType> copy(*this);
+                       return ++copy;
+               }
+
+               CompatibleType&                         operator*                                               (void) const
+               {
+                       return m_curBlock->elements[m_slotNdx];
+               }
+
+               operator                                        Iterator<const CompatibleType>  (void) const
+               {
+                       return Iterator<const CompatibleType>(m_curBlock, m_blockSize, m_slotNdx);
+               }
+
+       private:
+               Block*                  m_curBlock;
+               size_t                  m_blockSize;
+               size_t                  m_slotNdx;
+       };
+
+       typedef Iterator<const ElementType>     const_iterator;
+       typedef Iterator<ElementType>           iterator;
+
+       const_iterator                          begin                   (void) const;
+       iterator                                        begin                   (void);
+
+       const_iterator                          end                             (void) const;
+       iterator                                        end                             (void);
+};
+
+template<typename ElementType>
+AppendList<ElementType>::AppendList (size_t blockSize)
+       : m_blockSize   (blockSize)
+       , m_numElements (0)
+       , m_first               (new Block(0, blockSize))
+       , m_last                (m_first)
+{
+}
+
+template<typename ElementType>
+AppendList<ElementType>::~AppendList (void)
+{
+       size_t  elementNdx      = 0;
+       Block*  curBlock        = m_first;
+
+       while (curBlock)
+       {
+               Block* const    delBlock        = curBlock;
+
+               curBlock = delBlock->next;
+
+               // Call destructor for allocated elements
+               for (; elementNdx < min(m_numElements, delBlock->blockNdx*m_blockSize); ++elementNdx)
+                       delBlock->elements[elementNdx%m_blockSize].~ElementType();
+
+               delete delBlock;
+       }
+}
+
+template<typename ElementType>
+void AppendList<ElementType>::append (const ElementType& value)
+{
+       // Fetch curBlock first before allocating slot. Otherwise m_last might get updated before
+       // this thread gets chance of reading it, leading to curBlock->blockNdx > blockNdx.
+       Block*                  curBlock        = m_last;
+
+       deMemoryReadWriteFence();
+
+       {
+               const size_t    elementNdx      = deAtomicIncrementUSize(&m_numElements) - 1;
+               const size_t    blockNdx        = elementNdx / m_blockSize;
+               const size_t    slotNdx         = elementNdx - (blockNdx * m_blockSize);
+
+               while (curBlock->blockNdx != blockNdx)
+               {
+                       if (curBlock->next)
+                               curBlock = curBlock->next;
+                       else
+                       {
+                               // Other thread(s) are currently allocating additional block(s)
+                               deYield();
+                       }
+               }
+
+               // Did we allocate last slot? If so, add a new block
+               if (slotNdx+1 == m_blockSize)
+               {
+                       Block* const    newBlock        = new Block(blockNdx+1, m_blockSize);
+
+                       deMemoryReadWriteFence();
+
+                       // At this point if any other thread is trying to allocate more blocks
+                       // they are being blocked by curBlock->next being null. This guarantees
+                       // that this thread has exclusive modify access to m_last.
+                       m_last = newBlock;
+                       deMemoryReadWriteFence();
+
+                       // At this point other threads might have skipped to newBlock, but we
+                       // still have exclusive modify access to curBlock->next.
+                       curBlock->next = newBlock;
+                       deMemoryReadWriteFence();
+               }
+
+               new (&curBlock->elements[slotNdx]) ElementType(value);
+       }
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::const_iterator AppendList<ElementType>::begin (void) const
+{
+       return const_iterator(m_first, m_blockSize, 0);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::iterator AppendList<ElementType>::begin (void)
+{
+       return iterator(m_first, m_blockSize, 0);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::const_iterator AppendList<ElementType>::end (void) const
+{
+       return const_iterator(m_last, m_blockSize, m_numElements%m_blockSize);
+}
+
+template<typename ElementType>
+typename AppendList<ElementType>::iterator AppendList<ElementType>::end (void)
+{
+       return iterator(m_last, m_blockSize, m_numElements%m_blockSize);
+}
+
+void   AppendList_selfTest             (void);
+
+} // de
+
+#endif // _DEAPPENDLIST_HPP
index 73b84fb..13ac89e 100644 (file)
 namespace de
 {
 
-//!< Compute absolute value of x.
+//! Compute absolute value of x.
 template<typename T> inline T          abs                     (T x)                   { return x < T(0) ? -x : x; }
 
-//!< Get minimum of x and y.
+//! Get minimum of x and y.
 template<typename T> inline T          min                     (T x, T y)              { return x <= y ? x : y; }
 
-//!< Get maximum of x and y.
+//! Get maximum of x and y.
 template<typename T> inline T          max                     (T x, T y)              { return x >= y ? x : y; }
 
-//!< Clamp x in range a <= x <= b.
+//! Clamp x in range a <= x <= b.
 template<typename T> inline T          clamp           (T x, T a, T b) { DE_ASSERT(a <= b); return x < a ? a : (x > b ? b : x); }
 
-//!< Test if x is in bounds a <= x < b.
+//! Test if x is in bounds a <= x < b.
 template<typename T> inline bool       inBounds        (T x, T a, T b) { return a <= x && x < b; }
 
-//!< Test if x is in range a <= x <= b.
+//! Test if x is in range a <= x <= b.
 template<typename T> inline bool       inRange         (T x, T a, T b) { return a <= x && x <= b; }
 
 //! Helper for DE_CHECK() macros.
@@ -71,6 +71,14 @@ template<typename T> struct ArrayDeleter
        inline void operator() (T* ptr) const { delete[] ptr; }
 };
 
+//! Get required memory alignment for type
+template<typename T>
+size_t alignOf (void)
+{
+       struct PaddingCheck { deUint8 b; T t; };
+       return (size_t)DE_OFFSET_OF(PaddingCheck, t);
+}
+
 } // de
 
 /*--------------------------------------------------------------------*//*!
index 85f744a..665cd89 100644 (file)
@@ -45,6 +45,7 @@
 #include "deInt32.h"
 #include "deMath.h"
 #include "deSha1.h"
+#include "deMemory.h"
 
 // decpp
 #include "deBlockBuffer.hpp"
@@ -60,6 +61,7 @@
 #include "deStringUtil.hpp"
 #include "deSpinBarrier.hpp"
 #include "deSTLUtil.hpp"
+#include "deAppendList.hpp"
 
 namespace dit
 {
@@ -160,6 +162,7 @@ public:
                addChild(new SelfCheckCase(m_testCtx, "int32",  "deInt32_selfTest()",   deInt32_selfTest));
                addChild(new SelfCheckCase(m_testCtx, "math",   "deMath_selfTest()",    deMath_selfTest));
                addChild(new SelfCheckCase(m_testCtx, "sha1",   "deSha1_selfTest()",    deSha1_selfTest));
+               addChild(new SelfCheckCase(m_testCtx, "memory", "deMemory_selfTest()",  deMemory_selfTest));
        }
 };
 
@@ -186,6 +189,7 @@ public:
                addChild(new SelfCheckCase(m_testCtx, "string_util",                            "de::StringUtil_selfTest()",                    de::StringUtil_selfTest));
                addChild(new SelfCheckCase(m_testCtx, "spin_barrier",                           "de::SpinBarrier_selfTest()",                   de::SpinBarrier_selfTest));
                addChild(new SelfCheckCase(m_testCtx, "stl_util",                                       "de::STLUtil_selfTest()",                               de::STLUtil_selfTest));
+               addChild(new SelfCheckCase(m_testCtx, "append_list",                            "de::AppendList_selfTest()",                    de::AppendList_selfTest));
        }
 };