Cherry-pick SPIR-V assembly test improvements
authorPyry Haulos <phaulos@google.com>
Wed, 14 Jun 2017 18:54:31 +0000 (11:54 -0700)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Sun, 18 Jun 2017 14:40:29 +0000 (10:40 -0400)
These SPIR-V assembly test framework improvements are needed by new SPIR-V
tests.

Contains following commits, sans new tests:

e47e81cda3ab7215d6089f4f5f631fa4f4385e10
ca8cfd0d24bc210c1cfeb3ded0c2c0d2492aa66b
56bd1576eb438e10e8ccb22e17b08354fbf3bac7
56f121e90ff24a88b375db1a74c296d17dd97a74
05e91483c6f2f48b408ed1a638cbb32468ed8dfa
fc1e2f0942477676e92f7fe632ef441a90f570f8
318e6d042b1aaa15327342b39967f0ae97d23347
c35c2901d9d604631326eec11b80b3e6b7b7d55f
0d10dbfa6e176e18f69edcace62f921bb5225168
251a30e3cf94411b7453dd4e05cf24e1d45f579e
4fe79607bfac070a32d9554e3705379073e3672b
8977777244ce058cb79e1cf3b43e528322e8308c
6a51980397447d1f726e71d9126e47f84dc80a6f

Change-Id: Ibedf226d3160365651155327dac50e8e9987a6d4

16 files changed:
Android.mk
external/vulkancts/framework/vulkan/vkBasicTypes.inl
external/vulkancts/framework/vulkan/vkStrUtil.inl
external/vulkancts/framework/vulkan/vkStrUtilImpl.inl
external/vulkancts/framework/vulkan/vkStructTypes.inl
external/vulkancts/modules/vulkan/spirv_assembly/CMakeLists.txt
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.hpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp [new file with mode: 0644]
external/vulkancts/scripts/src/vulkan.h.in

index 51a82b4..d032bb7 100644 (file)
@@ -855,8 +855,10 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/sparse_resources/vktSparseResourcesTestsUtil.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.cpp \
+       external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.cpp \
+       external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp \
        external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutCase.cpp \
        external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutTests.cpp \
        external/vulkancts/modules/vulkan/synchronization/vktSynchronizationBasicEventTests.cpp \
index ca9cf41..ea03621 100644 (file)
@@ -157,6 +157,7 @@ enum VkStructureType
        VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR                          = 1000059007,
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR        = 1000059008,
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR        = 1000080000,
+       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR            = 1000083000,
        VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR                                                           = 1000084000,
        VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR            = 1000085000,
        VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE                                                     = 1000092000,
index cb8ccda..f65183f 100644 (file)
@@ -336,6 +336,7 @@ std::ostream&       operator<<      (std::ostream& s, const VkPhysicalDeviceMemoryPropertie
 std::ostream&  operator<<      (std::ostream& s, const VkSparseImageFormatProperties2KHR& value);
 std::ostream&  operator<<      (std::ostream& s, const VkPhysicalDeviceSparseImageFormatInfo2KHR& value);
 std::ostream&  operator<<      (std::ostream& s, const VkPhysicalDevicePushDescriptorPropertiesKHR& value);
+std::ostream&  operator<<      (std::ostream& s, const VkPhysicalDevice16BitStorageFeaturesKHR& value);
 std::ostream&  operator<<      (std::ostream& s, const VkRectLayerKHR& value);
 std::ostream&  operator<<      (std::ostream& s, const VkPresentRegionKHR& value);
 std::ostream&  operator<<      (std::ostream& s, const VkPresentRegionsKHR& value);
index e919afc..cfd9ed2 100644 (file)
@@ -170,6 +170,7 @@ const char* getStructureTypeName (VkStructureType value)
                case VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR:                    return "VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR";
                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR:  return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR";
                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR:  return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR";
+               case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR:              return "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR";
                case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR:                                                             return "VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR";
                case VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR:              return "VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR";
                case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:                                               return "VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE";
@@ -3415,6 +3416,19 @@ std::ostream& operator<< (std::ostream& s, const VkPhysicalDevicePushDescriptorP
        return s;
 }
 
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDevice16BitStorageFeaturesKHR& value)
+{
+       s << "VkPhysicalDevice16BitStorageFeaturesKHR = {\n";
+       s << "\tsType = " << value.sType << '\n';
+       s << "\tpNext = " << value.pNext << '\n';
+       s << "\tstorageUniformBufferBlock16 = " << value.storageUniformBufferBlock16 << '\n';
+       s << "\tstorageUniform16 = " << value.storageUniform16 << '\n';
+       s << "\tstoragePushConstant16 = " << value.storagePushConstant16 << '\n';
+       s << "\tstorageInputOutput16 = " << value.storageInputOutput16 << '\n';
+       s << '}';
+       return s;
+}
+
 std::ostream& operator<< (std::ostream& s, const VkRectLayerKHR& value)
 {
        s << "VkRectLayerKHR = {\n";
index 6cb7cb2..f01dabc 100644 (file)
@@ -1441,6 +1441,16 @@ struct VkPhysicalDevicePushDescriptorPropertiesKHR
        deUint32                maxPushDescriptors;
 };
 
+struct VkPhysicalDevice16BitStorageFeaturesKHR
+{
+       VkStructureType sType;
+       const void*             pNext;
+       VkBool32                storageUniformBufferBlock16;
+       VkBool32                storageUniform16;
+       VkBool32                storagePushConstant16;
+       VkBool32                storageInputOutput16;
+};
+
 struct VkRectLayerKHR
 {
        VkOffset2D      offset;
index 22eff93..b390b3c 100644 (file)
@@ -7,10 +7,14 @@ set(DEQP_VK_SPIRV_ASSEMBLY_SRCS
        vktSpvAsmComputeShaderCase.hpp
        vktSpvAsmComputeShaderTestUtil.cpp
        vktSpvAsmComputeShaderTestUtil.hpp
+       vktSpvAsmGraphicsShaderTestUtil.cpp
+       vktSpvAsmGraphicsShaderTestUtil.hpp
        vktSpvAsmInstructionTests.cpp
        vktSpvAsmInstructionTests.hpp
        vktSpvAsmTests.cpp
        vktSpvAsmTests.hpp
+       vktSpvAsmUtils.cpp
+       vktSpvAsmUtils.hpp
        )
 
 set(DEQP_VK_SPIRV_ASSEMBLY_LIBS
index be9cb24..4b6e8e0 100644 (file)
 #include "vktSpvAsmComputeShaderCase.hpp"
 
 #include "deSharedPtr.hpp"
+#include "deSTLUtil.hpp"
 
 #include "vkBuilderUtil.hpp"
 #include "vkMemUtil.hpp"
+#include "vkPlatform.hpp"
 #include "vkRefUtil.hpp"
 #include "vkQueryUtil.hpp"
 #include "vkTypeUtil.hpp"
@@ -49,15 +51,24 @@ typedef de::SharedPtr<BufferHandleUp>                               BufferHandleSp;
  * The memory is created as host visible and passed back as a vk::Allocation
  * instance via outMemory.
  *//*--------------------------------------------------------------------*/
-Move<VkBuffer> createBufferAndBindMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocator& allocator, size_t numBytes, AllocationMp* outMemory)
+Move<VkBuffer> createBufferAndBindMemory (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorType dtype, Allocator& allocator, size_t numBytes, AllocationMp* outMemory)
 {
-       const VkBufferCreateInfo bufferCreateInfo =
+       VkBufferUsageFlags                      usageBit                = (VkBufferUsageFlags)0;
+
+       switch (dtype)
+       {
+               case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: usageBit = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; break;
+               case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: usageBit = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; break;
+               default:                                                                DE_ASSERT(false);
+       }
+
+       const VkBufferCreateInfo bufferCreateInfo       =
        {
                VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   // sType
                DE_NULL,                                                                // pNext
                0u,                                                                             // flags
                numBytes,                                                               // size
-               VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,             // usage
+               usageBit,                                                               // usage
                VK_SHARING_MODE_EXCLUSIVE,                              // sharingMode
                0u,                                                                             // queueFamilyCount
                DE_NULL,                                                                // pQueueFamilyIndices
@@ -90,17 +101,16 @@ void fillMemoryWithValue (const DeviceInterface& vkdi, const VkDevice& device, A
 }
 
 /*--------------------------------------------------------------------*//*!
- * \brief Create a descriptor set layout with numBindings descriptors
+ * \brief Create a descriptor set layout with the given descriptor types
  *
- * All descriptors are created for shader storage buffer objects and
- * compute pipeline.
+ * All descriptors are created for compute pipeline.
  *//*--------------------------------------------------------------------*/
-Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkdi, const VkDevice& device, size_t numBindings)
+Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkdi, const VkDevice& device, const vector<VkDescriptorType>& dtypes)
 {
        DescriptorSetLayoutBuilder builder;
 
-       for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
-               builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
+       for (size_t bindingNdx = 0; bindingNdx < dtypes.size(); ++bindingNdx)
+               builder.addSingleBinding(dtypes[bindingNdx], VK_SHADER_STAGE_COMPUTE_BIT);
 
        return builder.build(vkdi, device);
 }
@@ -108,9 +118,9 @@ Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vk
 /*--------------------------------------------------------------------*//*!
  * \brief Create a pipeline layout with one descriptor set
  *//*--------------------------------------------------------------------*/
-Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorSetLayout descriptorSetLayout)
+Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorSetLayout descriptorSetLayout, const vkt::SpirVAssembly::BufferSp& pushConstants)
 {
-       const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
+       VkPipelineLayoutCreateInfo              createInfo      =
        {
                VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,  // sType
                DE_NULL,                                                                                // pNext
@@ -121,30 +131,47 @@ Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vkdi, const
                DE_NULL,                                                                                // pPushConstantRanges
        };
 
-       return createPipelineLayout(vkdi, device, &pipelineLayoutCreateInfo);
+       VkPushConstantRange                             range           =
+       {
+               VK_SHADER_STAGE_COMPUTE_BIT,                                    // stageFlags
+               0,                                                                                              // offset
+               0,                                                                                              // size
+       };
+
+       if (pushConstants != DE_NULL)
+       {
+               range.size                                                      = static_cast<deUint32>(pushConstants->getNumBytes());
+               createInfo.pushConstantRangeCount       = 1;
+               createInfo.pPushConstantRanges          = &range;
+       }
+
+       return createPipelineLayout(vkdi, device, &createInfo);
 }
 
 /*--------------------------------------------------------------------*//*!
- * \brief Create a one-time descriptor pool for one descriptor set
- *
- * The pool supports numDescriptors storage buffer descriptors.
+ * \brief Create a one-time descriptor pool for one descriptor set that
+ * support the given descriptor types.
  *//*--------------------------------------------------------------------*/
-inline Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkdi, const VkDevice& device, deUint32 numDescriptors)
+inline Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkdi, const VkDevice& device, const vector<VkDescriptorType>& dtypes)
 {
-       return DescriptorPoolBuilder()
-               .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, numDescriptors)
-               .build(vkdi, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, /* maxSets = */ 1);
+       DescriptorPoolBuilder builder;
+
+       for (size_t typeNdx = 0; typeNdx < dtypes.size(); ++typeNdx)
+               builder.addType(dtypes[typeNdx], 1);
+
+       return builder.build(vkdi, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, /* maxSets = */ 1);
 }
 
 /*--------------------------------------------------------------------*//*!
  * \brief Create a descriptor set
  *
- * The descriptor set's layout should contain numViews descriptors.
- * All the descriptors represent buffer views, and they are sequentially
- * binded to binding point starting from 0.
+ * The descriptor set's layout contains the given descriptor types,
+ * sequentially binded to binding points starting from 0.
  *//*--------------------------------------------------------------------*/
-Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorPool pool, VkDescriptorSetLayout layout, size_t numViews, const vector<VkDescriptorBufferInfo>& descriptorInfos)
+Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorPool pool, VkDescriptorSetLayout layout, const vector<VkDescriptorType>& dtypes, const vector<VkDescriptorBufferInfo>& descriptorInfos)
 {
+       DE_ASSERT(dtypes.size() == descriptorInfos.size());
+
        const VkDescriptorSetAllocateInfo       allocInfo       =
        {
                VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@@ -157,8 +184,8 @@ Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const Vk
        Move<VkDescriptorSet>                           descriptorSet   = allocateDescriptorSet(vkdi, device, &allocInfo);
        DescriptorSetUpdateBuilder                      builder;
 
-       for (deUint32 descriptorNdx = 0; descriptorNdx < numViews; ++descriptorNdx)
-               builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descriptorNdx), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfos[descriptorNdx]);
+       for (deUint32 descriptorNdx = 0; descriptorNdx < dtypes.size(); ++descriptorNdx)
+               builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descriptorNdx), dtypes[descriptorNdx], &descriptorInfos[descriptorNdx]);
        builder.update(vkdi, device);
 
        return descriptorSet;
@@ -246,18 +273,24 @@ namespace SpirVAssembly
 class SpvAsmComputeShaderInstance : public TestInstance
 {
 public:
-                                                               SpvAsmComputeShaderInstance     (Context& ctx, const ComputeShaderSpec& spec);
-       tcu::TestStatus                         iterate                                         (void);
+                                                                               SpvAsmComputeShaderInstance     (Context& ctx, const ComputeShaderSpec& spec, const ComputeTestFeatures features);
+       tcu::TestStatus                                         iterate                                         (void);
 
 private:
-       const ComputeShaderSpec&        m_shaderSpec;
+       const Unique<VkDevice>                          m_device;
+       const DeviceDriver                                      m_deviceInterface;
+       const VkQueue                                           m_queue;
+       const de::UniquePtr<vk::Allocator>      m_allocator;
+       const ComputeShaderSpec&                        m_shaderSpec;
+       const ComputeTestFeatures                       m_features;
 };
 
 // ComputeShaderTestCase implementations
 
-SpvAsmComputeShaderCase::SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec)
+SpvAsmComputeShaderCase::SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec, const ComputeTestFeatures features)
        : TestCase              (testCtx, name, description)
        , m_shaderSpec  (spec)
+       , m_features    (features)
 {
 }
 
@@ -268,40 +301,72 @@ void SpvAsmComputeShaderCase::initPrograms (SourceCollections& programCollection
 
 TestInstance* SpvAsmComputeShaderCase::createInstance (Context& ctx) const
 {
-       return new SpvAsmComputeShaderInstance(ctx, m_shaderSpec);
+       return new SpvAsmComputeShaderInstance(ctx, m_shaderSpec, m_features);
 }
 
 // ComputeShaderTestInstance implementations
 
-SpvAsmComputeShaderInstance::SpvAsmComputeShaderInstance (Context& ctx, const ComputeShaderSpec& spec)
-       : TestInstance  (ctx)
-       , m_shaderSpec  (spec)
+SpvAsmComputeShaderInstance::SpvAsmComputeShaderInstance (Context& ctx, const ComputeShaderSpec& spec, const ComputeTestFeatures features)
+       : TestInstance          (ctx)
+       , m_device                      (createDeviceWithExtensions(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), ctx.getUniversalQueueFamilyIndex(), ctx.getDeviceExtensions(), spec.extensions))
+       , m_deviceInterface     (ctx.getInstanceInterface(), *m_device)
+       , m_queue                       (getDeviceQueue(m_deviceInterface, *m_device, ctx.getUniversalQueueFamilyIndex(), 0))
+       , m_allocator           (createAllocator(ctx.getInstanceInterface(), ctx.getPhysicalDevice(), m_deviceInterface, *m_device))
+       , m_shaderSpec          (spec)
+       , m_features            (features)
 {
 }
 
 tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
 {
-       const DeviceInterface&                          vkdi                            = m_context.getDeviceInterface();
-       const VkDevice&                                         device                          = m_context.getDevice();
-       Allocator&                                                      allocator                       = m_context.getDefaultAllocator();
+       const VkPhysicalDeviceFeatures&         features                        = m_context.getDeviceFeatures();
+       const DeviceInterface&                          vkdi                            = m_deviceInterface;
+       const VkDevice&                                         device                          = *m_device;
+       Allocator&                                                      allocator                       = *m_allocator;
+
+       if ((m_features == COMPUTE_TEST_USES_INT16 || m_features == COMPUTE_TEST_USES_INT16_INT64) && !features.shaderInt16)
+       {
+               TCU_THROW(NotSupportedError, "shaderInt16 feature is not supported");
+       }
+
+       if ((m_features == COMPUTE_TEST_USES_INT64 || m_features == COMPUTE_TEST_USES_INT16_INT64) && !features.shaderInt64)
+       {
+               TCU_THROW(NotSupportedError, "shaderInt64 feature is not supported");
+       }
+
+       {
+               const InstanceInterface&                        vki                                     = m_context.getInstanceInterface();
+               const VkPhysicalDevice                          physicalDevice          = m_context.getPhysicalDevice();
+
+               // 16bit storage features
+               {
+                       if (!is16BitStorageFeaturesSupported(vki, physicalDevice, m_context.getInstanceExtensions(), m_shaderSpec.requestedExtensionFeatures.ext16BitStorage))
+                               TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
+               }
+       }
 
        vector<AllocationSp>                            inputAllocs;
        vector<AllocationSp>                            outputAllocs;
        vector<BufferHandleSp>                          inputBuffers;
        vector<BufferHandleSp>                          outputBuffers;
        vector<VkDescriptorBufferInfo>          descriptorInfos;
+       vector<VkDescriptorType>                        descriptorTypes;
 
        DE_ASSERT(!m_shaderSpec.outputs.empty());
-       const size_t                                            numBuffers                      = m_shaderSpec.inputs.size() + m_shaderSpec.outputs.size();
 
        // Create buffer object, allocate storage, and create view for all input/output buffers.
 
-       for (size_t inputNdx = 0; inputNdx < m_shaderSpec.inputs.size(); ++inputNdx)
+       for (deUint32 inputNdx = 0; inputNdx < m_shaderSpec.inputs.size(); ++inputNdx)
        {
+               if (m_shaderSpec.inputTypes.count(inputNdx) != 0)
+                       descriptorTypes.push_back(m_shaderSpec.inputTypes.at(inputNdx));
+               else
+                       descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+
                AllocationMp            alloc;
                const BufferSp&         input           = m_shaderSpec.inputs[inputNdx];
                const size_t            numBytes        = input->getNumBytes();
-               BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
+               BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, descriptorTypes.back(), allocator, numBytes, &alloc));
 
                setMemory(vkdi, device, &*alloc, numBytes, input->data());
                descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
@@ -309,12 +374,14 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
                inputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
        }
 
-       for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+       for (deUint32 outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
        {
+               descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+
                AllocationMp            alloc;
                const BufferSp&         output          = m_shaderSpec.outputs[outputNdx];
                const size_t            numBytes        = output->getNumBytes();
-               BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
+               BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, descriptorTypes.back(), allocator, numBytes, &alloc));
 
                fillMemoryWithValue(vkdi, device, &*alloc, numBytes, 0xff);
                descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
@@ -324,10 +391,10 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
 
        // Create layouts and descriptor set.
 
-       Unique<VkDescriptorSetLayout>           descriptorSetLayout     (createDescriptorSetLayout(vkdi, device, numBuffers));
-       Unique<VkPipelineLayout>                        pipelineLayout          (createPipelineLayout(vkdi, device, *descriptorSetLayout));
-       Unique<VkDescriptorPool>                        descriptorPool          (createDescriptorPool(vkdi, device, (deUint32)numBuffers));
-       Unique<VkDescriptorSet>                         descriptorSet           (createDescriptorSet(vkdi, device, *descriptorPool, *descriptorSetLayout, numBuffers, descriptorInfos));
+       Unique<VkDescriptorSetLayout>           descriptorSetLayout     (createDescriptorSetLayout(vkdi, device, descriptorTypes));
+       Unique<VkPipelineLayout>                        pipelineLayout          (createPipelineLayout(vkdi, device, *descriptorSetLayout, m_shaderSpec.pushConstants));
+       Unique<VkDescriptorPool>                        descriptorPool          (createDescriptorPool(vkdi, device, descriptorTypes));
+       Unique<VkDescriptorSet>                         descriptorSet           (createDescriptorSet(vkdi, device, *descriptorPool, *descriptorSetLayout, descriptorTypes, descriptorInfos));
 
        // Create compute shader and pipeline.
 
@@ -354,6 +421,13 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
        VK_CHECK(vkdi.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
        vkdi.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
        vkdi.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
+       if (m_shaderSpec.pushConstants != DE_NULL)
+       {
+               const deUint32  size    = static_cast<deUint32>(m_shaderSpec.pushConstants->getNumBytes());
+               const void*             data    = m_shaderSpec.pushConstants->data();
+
+               vkdi.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, /* offset = */ 0, /* size = */ size, data);
+       }
        vkdi.cmdDispatch(*cmdBuffer, numWorkGroups.x(), numWorkGroups.y(), numWorkGroups.z());
        VK_CHECK(vkdi.endCommandBuffer(*cmdBuffer));
 
@@ -374,14 +448,14 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
                (const VkSemaphore*)DE_NULL,
        };
 
-       VK_CHECK(vkdi.queueSubmit(m_context.getUniversalQueue(), 1, &submitInfo, *cmdCompleteFence));
+       VK_CHECK(vkdi.queueSubmit(m_queue, 1, &submitInfo, *cmdCompleteFence));
        VK_CHECK(vkdi.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
 
        // Check output.
        if (m_shaderSpec.verifyIO)
        {
                if (!(*m_shaderSpec.verifyIO)(m_shaderSpec.inputs, outputAllocs, m_shaderSpec.outputs, m_context.getTestContext().getLog()))
-                       return tcu::TestStatus::fail("Output doesn't match with expected");
+                       return tcu::TestStatus(m_shaderSpec.failResult, m_shaderSpec.failMessage);
        }
        else
        {
@@ -389,55 +463,11 @@ tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
                {
                        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(m_shaderSpec.failResult, m_shaderSpec.failMessage);
                }
        }
 
-       return tcu::TestStatus::pass("Ouput match with expected");
-}
-
-class ConvertTestInstance : public SpvAsmComputeShaderInstance
-{
-public:
-                                               ConvertTestInstance     (Context& ctx, const ComputeShaderSpec& spec, const ConvertTestFeatures features);
-       tcu::TestStatus         iterate                         (void);
-private:
-       const ConvertTestFeatures       m_features;
-};
-
-ConvertTestInstance::ConvertTestInstance (Context& ctx, const ComputeShaderSpec& spec, const ConvertTestFeatures features)
-       : SpvAsmComputeShaderInstance   (ctx, spec)
-       , m_features                                    (features)
-{
-}
-
-tcu::TestStatus ConvertTestInstance::iterate (void)
-{
-       const VkPhysicalDeviceFeatures&         features = m_context.getDeviceFeatures();
-
-       if ((m_features == CONVERT_TEST_USES_INT16 || m_features == CONVERT_TEST_USES_INT16_INT64) && !features.shaderInt16)
-       {
-               throw tcu::NotSupportedError("shaderInt16 feature is not supported");
-       }
-
-       if ((m_features == CONVERT_TEST_USES_INT64 || m_features == CONVERT_TEST_USES_INT16_INT64) && !features.shaderInt64)
-       {
-               throw tcu::NotSupportedError("shaderInt64 feature is not supported");
-       }
-
-       return SpvAsmComputeShaderInstance::iterate();
-}
-
-ConvertTestCase::ConvertTestCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec, const ConvertTestFeatures features)
-       : SpvAsmComputeShaderCase       (testCtx, name, description, spec)
-       , m_shaderSpec                          (spec)
-       , m_features                            (features)
-{
-}
-
-TestInstance* ConvertTestCase::createInstance (Context& ctx) const
-{
-       return new ConvertTestInstance(ctx, m_shaderSpec, m_features);
+       return tcu::TestStatus::pass("Output match with expected");
 }
 
 } // SpirVAssembly
index bd70ffc..50c69e9 100644 (file)
@@ -33,32 +33,24 @@ namespace vkt
 namespace SpirVAssembly
 {
 
+enum ComputeTestFeatures
+{
+       COMPUTE_TEST_USES_NONE,
+       COMPUTE_TEST_USES_INT16,
+       COMPUTE_TEST_USES_INT64,
+       COMPUTE_TEST_USES_INT16_INT64,
+};
+
 class SpvAsmComputeShaderCase : public TestCase
 {
 public:
-                                               SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec);
+                                               SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec, const ComputeTestFeatures features = COMPUTE_TEST_USES_NONE);
        void                            initPrograms                    (vk::SourceCollections& programCollection) const;
        TestInstance*           createInstance                  (Context& ctx) const;
 
 private:
        ComputeShaderSpec       m_shaderSpec;
-};
-
-enum ConvertTestFeatures
-{
-       CONVERT_TEST_USES_INT16,
-       CONVERT_TEST_USES_INT64,
-       CONVERT_TEST_USES_INT16_INT64,
-};
-
-class ConvertTestCase : public SpvAsmComputeShaderCase
-{
-public:
-                                               ConvertTestCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec, const ConvertTestFeatures features);
-       TestInstance*           createInstance  (Context& ctx) const;
-private:
-       ComputeShaderSpec                       m_shaderSpec;
-       const ConvertTestFeatures       m_features;
+       const ComputeTestFeatures       m_features;
 };
 
 } // SpirVAssembly
index 5727fb5..2d60026 100644 (file)
 
 #include "vktSpvAsmComputeShaderTestUtil.hpp"
 
-DE_EMPTY_CPP_FILE
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+const char* getComputeAsmShaderPreamble (void)
+{
+       return
+               "OpCapability Shader\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint GLCompute %main \"main\" %id\n"
+               "OpExecutionMode %main LocalSize 1 1 1\n";
+}
+
+const char* getComputeAsmCommonTypes (void)
+{
+       return
+               "%bool      = OpTypeBool\n"
+               "%void      = OpTypeVoid\n"
+               "%voidf     = OpTypeFunction %void\n"
+               "%u32       = OpTypeInt 32 0\n"
+               "%i32       = OpTypeInt 32 1\n"
+               "%f32       = OpTypeFloat 32\n"
+               "%uvec3     = OpTypeVector %u32 3\n"
+               "%fvec3     = OpTypeVector %f32 3\n"
+               "%uvec3ptr  = OpTypePointer Input %uvec3\n"
+               "%i32ptr    = OpTypePointer Uniform %i32\n"
+               "%f32ptr    = OpTypePointer Uniform %f32\n"
+               "%i32arr    = OpTypeRuntimeArray %i32\n"
+               "%f32arr    = OpTypeRuntimeArray %f32\n";
+}
+
+const char* getComputeAsmInputOutputBuffer (void)
+{
+       return
+               "%buf     = OpTypeStruct %f32arr\n"
+               "%bufptr  = OpTypePointer Uniform %buf\n"
+               "%indata    = OpVariable %bufptr Uniform\n"
+               "%outdata   = OpVariable %bufptr Uniform\n";
+}
+
+const char* getComputeAsmInputOutputBufferTraits (void)
+{
+       return
+               "OpDecorate %buf BufferBlock\n"
+               "OpDecorate %indata DescriptorSet 0\n"
+               "OpDecorate %indata Binding 0\n"
+               "OpDecorate %outdata DescriptorSet 0\n"
+               "OpDecorate %outdata Binding 1\n"
+               "OpDecorate %f32arr ArrayStride 4\n"
+               "OpMemberDecorate %buf 0 Offset 0\n";
+}
+
+} // SpirVAssembly
+} // vkt
index 4c6b644..09adf1d 100644 (file)
  *//*--------------------------------------------------------------------*/
 
 #include "deDefs.h"
+#include "deFloat16.h"
 #include "deSharedPtr.hpp"
 #include "tcuTestLog.hpp"
 #include "tcuVector.hpp"
 #include "vkMemUtil.hpp"
+#include "vktSpvAsmUtils.hpp"
 
 #include <string>
 #include <vector>
+#include <map>
 
 using namespace vk;
 
@@ -80,6 +83,10 @@ typedef Buffer<float>                Float32Buffer;
 typedef Buffer<deInt32>                Int32Buffer;
 typedef Buffer<tcu::Vec4>      Vec4Buffer;
 
+typedef bool (*ComputeVerifyIOFunc) (const std::vector<BufferSp>&              inputs,
+                                                                        const std::vector<AllocationSp>&       outputAllocations,
+                                                                        const std::vector<BufferSp>&           expectedOutputs,
+                                                                        tcu::TestLog&                                          log);
 
 /*--------------------------------------------------------------------*//*!
  * \brief Specification for a compute shader.
@@ -89,24 +96,54 @@ typedef Buffer<tcu::Vec4>   Vec4Buffer;
  *//*--------------------------------------------------------------------*/
 struct ComputeShaderSpec
 {
-       std::string                             assembly;
-       std::string                             entryPoint;
-       std::vector<BufferSp>   inputs;
-       std::vector<BufferSp>   outputs;
-       tcu::IVec3                              numWorkGroups;
-       std::vector<deUint32>   specConstants;
+       std::string                                                             assembly;
+       std::string                                                             entryPoint;
+       std::vector<BufferSp>                                   inputs;
+       // Mapping from input index (in the inputs field) to the descriptor type.
+       std::map<deUint32, VkDescriptorType>    inputTypes;
+       std::vector<BufferSp>                                   outputs;
+       tcu::IVec3                                                              numWorkGroups;
+       std::vector<deUint32>                                   specConstants;
+       BufferSp                                                                pushConstants;
+       std::vector<std::string>                                extensions;
+       ExtensionFeatures                                               requestedExtensionFeatures;
+       qpTestResult                                                    failResult;
+       std::string                                                             failMessage;
        // 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, tcu::TestLog& log);
-                                                       ComputeShaderSpec()
-                                                               : entryPoint    ("main")
-                                                               , verifyIO              (DE_NULL)
-                                                       {}
-
+       // case is assumed to have failed. Exact meaning of failure can be customized with failResult.
+       ComputeVerifyIOFunc                                             verifyIO;
+
+                                                                                       ComputeShaderSpec (void)
+                                                                                               : entryPoint                                    ("main")
+                                                                                               , pushConstants                                 (DE_NULL)
+                                                                                               , requestedExtensionFeatures    ()
+                                                                                               , failResult                                    (QP_TEST_RESULT_FAIL)
+                                                                                               , failMessage                                   ("Output doesn't match with expected")
+                                                                                               , verifyIO                                              (DE_NULL)
+                                                                                       {}
 };
 
+/*--------------------------------------------------------------------*//*!
+ * \brief Helper functions for SPIR-V assembly shared by various tests
+ *//*--------------------------------------------------------------------*/
+
+const char* getComputeAsmShaderPreamble                                (void);
+const char* getComputeAsmCommonTypes                           (void);
+
+/*--------------------------------------------------------------------*//*!
+ * Declares two uniform variables (indata, outdata) of type
+ * "struct { float[] }". Depends on type "f32arr" (for "float[]").
+ *//*--------------------------------------------------------------------*/
+const char* getComputeAsmInputOutputBuffer                     (void);
+/*--------------------------------------------------------------------*//*!
+ * 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.
+ *//*--------------------------------------------------------------------*/
+const char* getComputeAsmInputOutputBufferTraits       (void);
+
 } // SpirVAssembly
 } // vkt
 
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.cpp
new file mode 100644 (file)
index 0000000..a62ee13
--- /dev/null
@@ -0,0 +1,3490 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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 Graphics pipeline for SPIR-V assembly tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmGraphicsShaderTestUtil.hpp"
+
+#include "tcuFloat.hpp"
+#include "tcuStringTemplate.hpp"
+
+#include "vkDefs.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "deRandom.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+using namespace vk;
+using std::map;
+using std::string;
+using std::vector;
+using tcu::Float16;
+using tcu::Float32;
+using tcu::IVec3;
+using tcu::IVec4;
+using tcu::RGBA;
+using tcu::TestLog;
+using tcu::TestStatus;
+using tcu::Vec4;
+using de::UniquePtr;
+using tcu::StringTemplate;
+using tcu::Vec4;
+
+deUint32 IFDataType::getElementNumBytes (void) const
+{
+       if (elementType < NUMBERTYPE_END32)
+               return 4;
+
+       return 2;
+}
+
+VkFormat IFDataType::getVkFormat (void) const
+{
+       if (numElements == 1)
+       {
+               switch (elementType)
+               {
+                       case NUMBERTYPE_FLOAT32:        return VK_FORMAT_R32_SFLOAT;
+                       case NUMBERTYPE_INT32:          return VK_FORMAT_R32_SINT;
+                       case NUMBERTYPE_UINT32:         return VK_FORMAT_R32_UINT;
+                       case NUMBERTYPE_FLOAT16:        return VK_FORMAT_R16_SFLOAT;
+                       case NUMBERTYPE_INT16:          return VK_FORMAT_R16_SINT;
+                       case NUMBERTYPE_UINT16:         return VK_FORMAT_R16_UINT;
+                       default:                                        break;
+               }
+       }
+       else if (numElements == 2)
+       {
+               switch (elementType)
+               {
+                       case NUMBERTYPE_FLOAT32:        return VK_FORMAT_R32G32_SFLOAT;
+                       case NUMBERTYPE_INT32:          return VK_FORMAT_R32G32_SINT;
+                       case NUMBERTYPE_UINT32:         return VK_FORMAT_R32G32_UINT;
+                       case NUMBERTYPE_FLOAT16:        return VK_FORMAT_R16G16_SFLOAT;
+                       case NUMBERTYPE_INT16:          return VK_FORMAT_R16G16_SINT;
+                       case NUMBERTYPE_UINT16:         return VK_FORMAT_R16G16_UINT;
+                       default:                                        break;
+               }
+       }
+       else if (numElements == 3)
+       {
+               switch (elementType)
+               {
+                       case NUMBERTYPE_FLOAT32:        return VK_FORMAT_R32G32B32_SFLOAT;
+                       case NUMBERTYPE_INT32:          return VK_FORMAT_R32G32B32_SINT;
+                       case NUMBERTYPE_UINT32:         return VK_FORMAT_R32G32B32_UINT;
+                       case NUMBERTYPE_FLOAT16:        return VK_FORMAT_R16G16B16_SFLOAT;
+                       case NUMBERTYPE_INT16:          return VK_FORMAT_R16G16B16_SINT;
+                       case NUMBERTYPE_UINT16:         return VK_FORMAT_R16G16B16_UINT;
+                       default:                                        break;
+               }
+       }
+       else if (numElements == 4)
+       {
+               switch (elementType)
+               {
+                       case NUMBERTYPE_FLOAT32:        return VK_FORMAT_R32G32B32A32_SFLOAT;
+                       case NUMBERTYPE_INT32:          return VK_FORMAT_R32G32B32A32_SINT;
+                       case NUMBERTYPE_UINT32:         return VK_FORMAT_R32G32B32A32_UINT;
+                       case NUMBERTYPE_FLOAT16:        return VK_FORMAT_R16G16B16A16_SFLOAT;
+                       case NUMBERTYPE_INT16:          return VK_FORMAT_R16G16B16A16_SINT;
+                       case NUMBERTYPE_UINT16:         return VK_FORMAT_R16G16B16A16_UINT;
+                       default:                                        break;
+               }
+       }
+
+       DE_ASSERT(false);
+       return VK_FORMAT_UNDEFINED;
+}
+
+tcu::TextureFormat IFDataType::getTextureFormat (void) const
+{
+       tcu::TextureFormat::ChannelType         ct      = tcu::TextureFormat::CHANNELTYPE_LAST;
+       tcu::TextureFormat::ChannelOrder        co      = tcu::TextureFormat::CHANNELORDER_LAST;
+
+       switch (elementType)
+       {
+               case NUMBERTYPE_FLOAT32:        ct = tcu::TextureFormat::FLOAT;                         break;
+               case NUMBERTYPE_INT32:          ct = tcu::TextureFormat::SIGNED_INT32;          break;
+               case NUMBERTYPE_UINT32:         ct = tcu::TextureFormat::UNSIGNED_INT32;        break;
+               case NUMBERTYPE_FLOAT16:        ct = tcu::TextureFormat::HALF_FLOAT;            break;
+               case NUMBERTYPE_INT16:          ct = tcu::TextureFormat::SIGNED_INT16;          break;
+               case NUMBERTYPE_UINT16:         ct = tcu::TextureFormat::UNSIGNED_INT16;        break;
+               default:                                        DE_ASSERT(false);
+       }
+
+       switch (numElements)
+       {
+               case 1:                         co = tcu::TextureFormat::R;                                     break;
+               case 2:                         co = tcu::TextureFormat::RG;                            break;
+               case 3:                         co = tcu::TextureFormat::RGB;                           break;
+               case 4:                         co = tcu::TextureFormat::RGBA;                          break;
+               default:                        DE_ASSERT(false);
+       }
+
+       return tcu::TextureFormat(co, ct);
+}
+
+string IFDataType::str (void) const
+{
+       string  ret;
+
+       switch (elementType)
+       {
+               case NUMBERTYPE_FLOAT32:        ret = "f32"; break;
+               case NUMBERTYPE_INT32:          ret = "i32"; break;
+               case NUMBERTYPE_UINT32:         ret = "u32"; break;
+               case NUMBERTYPE_FLOAT16:        ret = "f16"; break;
+               case NUMBERTYPE_INT16:          ret = "i16"; break;
+               case NUMBERTYPE_UINT16:         ret = "u16"; break;
+               default:                                        DE_ASSERT(false);
+       }
+
+       if (numElements == 1)
+               return ret;
+
+       return string("v") + numberToString(numElements) + ret;
+}
+
+VkBufferUsageFlagBits getMatchingBufferUsageFlagBit(VkDescriptorType dType)
+{
+       switch (dType)
+       {
+               case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+               case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+               default:                                                                DE_ASSERT(0 && "not implemented");
+       }
+       return (VkBufferUsageFlagBits)0;
+}
+
+InstanceContext::InstanceContext (const RGBA                                           (&inputs)[4],
+                                                                 const RGBA                                            (&outputs)[4],
+                                                                 const map<string, string>&            testCodeFragments_,
+                                                                 const StageToSpecConstantMap&         specConstants_,
+                                                                 const PushConstants&                          pushConsants_,
+                                                                 const GraphicsResources&                      resources_,
+                                                                 const GraphicsInterfaces&                     interfaces_,
+                                                                 const vector<string>&                         extensions_,
+                                                                 const vector<string>&                         features_,
+                                                                 ExtensionFeatures                                     extensionFeatures_)
+       : testCodeFragments                             (testCodeFragments_)
+       , specConstants                                 (specConstants_)
+       , hasTessellation                               (false)
+       , requiredStages                                (static_cast<VkShaderStageFlagBits>(0))
+       , requiredDeviceExtensions              (extensions_)
+       , requiredDeviceFeatures                (features_)
+       , requestedExtensionFeatures    (extensionFeatures_)
+       , pushConstants                                 (pushConsants_)
+       , resources                                             (resources_)
+       , interfaces                                    (interfaces_)
+       , failResult                                    (QP_TEST_RESULT_FAIL)
+       , failMessageTemplate                   ("${reason}")
+{
+       inputColors[0]          = inputs[0];
+       inputColors[1]          = inputs[1];
+       inputColors[2]          = inputs[2];
+       inputColors[3]          = inputs[3];
+
+       outputColors[0]         = outputs[0];
+       outputColors[1]         = outputs[1];
+       outputColors[2]         = outputs[2];
+       outputColors[3]         = outputs[3];
+}
+
+InstanceContext::InstanceContext (const InstanceContext& other)
+       : moduleMap                                             (other.moduleMap)
+       , testCodeFragments                             (other.testCodeFragments)
+       , specConstants                                 (other.specConstants)
+       , hasTessellation                               (other.hasTessellation)
+       , requiredStages                                (other.requiredStages)
+       , requiredDeviceExtensions              (other.requiredDeviceExtensions)
+       , requiredDeviceFeatures                (other.requiredDeviceFeatures)
+       , requestedExtensionFeatures    (other.requestedExtensionFeatures)
+       , pushConstants                                 (other.pushConstants)
+       , resources                                             (other.resources)
+       , interfaces                                    (other.interfaces)
+       , failResult                                    (other.failResult)
+       , failMessageTemplate                   (other.failMessageTemplate)
+{
+       inputColors[0]          = other.inputColors[0];
+       inputColors[1]          = other.inputColors[1];
+       inputColors[2]          = other.inputColors[2];
+       inputColors[3]          = other.inputColors[3];
+
+       outputColors[0]         = other.outputColors[0];
+       outputColors[1]         = other.outputColors[1];
+       outputColors[2]         = other.outputColors[2];
+       outputColors[3]         = other.outputColors[3];
+}
+
+string InstanceContext::getSpecializedFailMessage (const string& failureReason)
+{
+       map<string, string>             parameters;
+       parameters["reason"]    = failureReason;
+       return StringTemplate(failMessageTemplate).specialize(parameters);
+}
+
+ShaderElement::ShaderElement (const string&                            moduleName_,
+                                                         const string&                         entryPoint_,
+                                                         VkShaderStageFlagBits         shaderStage_)
+               : moduleName(moduleName_)
+               , entryName(entryPoint_)
+               , stage(shaderStage_)
+{
+}
+
+void getDefaultColors (RGBA (&colors)[4])
+{
+       colors[0] = RGBA::white();
+       colors[1] = RGBA::red();
+       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);
+}
+
+// For the current InstanceContext, constructs the required modules and shader stage create infos.
+void createPipelineShaderStages (const DeviceInterface&                                                vk,
+                                                                const VkDevice                                                         vkDevice,
+                                                                InstanceContext&                                                       instance,
+                                                                Context&                                                                       context,
+                                                                vector<ModuleHandleSp>&                                        modules,
+                                                                vector<VkPipelineShaderStageCreateInfo>&       createInfos)
+{
+       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;
+                       const VkPipelineShaderStageCreateInfo   shaderParam             =
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    //      VkStructureType                 sType;
+                               DE_NULL,                                                                                                //      const void*                             pNext;
+                               (VkPipelineShaderStageCreateFlags)0,
+                               stage.second,                                                                                   //      VkShaderStageFlagBits   stage;
+                               **modules.back(),                                                                               //      VkShaderModule                  module;
+                               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"                                                                                                                                       \
+       "%v2i32 = OpTypeVector %i32 2\n"                                                                                                                        \
+       "%v2u32 = OpTypeVector %u32 2\n"                                                                                                                        \
+       "%v2f32 = OpTypeVector %f32 2\n"                                                                                                                        \
+       "%v3f32 = OpTypeVector %f32 3\n"                                                                                                                        \
+       "%v4i32 = OpTypeVector %i32 4\n"                                                                                                                        \
+       "%v4u32 = OpTypeVector %u32 4\n"                                                                                                                        \
+       "%v4f32 = OpTypeVector %f32 4\n"                                                                                                                        \
+       "%v4bool = OpTypeVector %bool 4\n"                                                                                                                      \
+                                                                                                                                                                                               \
+       "%v4f32_function = OpTypeFunction %v4f32 %v4f32\n"                                                                                      \
+       "%bool_function = OpTypeFunction %bool\n"                                                                                                       \
+       "%fun = OpTypeFunction %void\n"                                                                                                                         \
+                                                                                                                                                                                               \
+       "%ip_f32 = OpTypePointer Input %f32\n"                                                                                                          \
+       "%ip_i32 = OpTypePointer Input %i32\n"                                                                                                          \
+       "%ip_u32 = OpTypePointer Input %u32\n"                                                                                                          \
+       "%ip_v3f32 = OpTypePointer Input %v3f32\n"                                                                                                      \
+       "%ip_v2f32 = OpTypePointer Input %v2f32\n"                                                                                                      \
+       "%ip_v2i32 = OpTypePointer Input %v2i32\n"                                                                                                      \
+       "%ip_v2u32 = OpTypePointer Input %v2u32\n"                                                                                                      \
+       "%ip_v4f32 = OpTypePointer Input %v4f32\n"                                                                                                      \
+       "%ip_v4i32 = OpTypePointer Input %v4i32\n"                                                                                                      \
+       "%ip_v4u32 = OpTypePointer Input %v4u32\n"                                                                                                      \
+                                                                                                                                                                                               \
+       "%op_f32 = OpTypePointer Output %f32\n"                                                                                                         \
+       "%op_i32 = OpTypePointer Output %i32\n"                                                                                                         \
+       "%op_u32 = OpTypePointer Output %u32\n"                                                                                                         \
+       "%op_v2f32 = OpTypePointer Output %v2f32\n"                                                                                                     \
+       "%op_v2i32 = OpTypePointer Output %v2i32\n"                                                                                                     \
+       "%op_v2u32 = OpTypePointer Output %v2u32\n"                                                                                                     \
+       "%op_v4f32 = OpTypePointer Output %v4f32\n"                                                                                                     \
+       "%op_v4i32 = OpTypePointer Output %v4i32\n"                                                                                                     \
+       "%op_v4u32 = OpTypePointer Output %v4u32\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_f32_7 = OpConstant %f32 7.0\n"                                                                                                                      \
+       "%c_f32_8 = OpConstant %f32 8.0\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
+// on fragments, which must (at least) map "testfun" to an OpFunction definition
+// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
+// with "BP_" to avoid collisions with fragments.
+//
+// It corresponds roughly to this GLSL:
+//;
+// layout(location = 0) in vec4 position;
+// layout(location = 1) in vec4 color;
+// layout(location = 1) out highp vec4 vtxColor;
+// void main (void) { gl_Position = position; vtxColor = test_func(color); }
+string makeVertexShaderAssembly(const map<string, string>& fragments)
+{
+// \todo [2015-11-23 awoloszyn] Remove OpName once these have stabalized
+       static const char vertexShaderBoilerplate[] =
+               "OpCapability Shader\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\n"
+               "${capability:opt}\n"
+               "${extension:opt}\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Vertex %main \"main\" %BP_stream %BP_position %BP_vtx_color %BP_color %BP_gl_VertexIndex %BP_gl_InstanceIndex ${IF_entrypoint:opt} \n"
+               "${debug:opt}\n"
+               "OpName %main \"main\"\n"
+               "OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
+               "OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
+               "OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+               "OpName %BP_stream \"\"\n"
+               "OpName %BP_position \"position\"\n"
+               "OpName %BP_vtx_color \"vtxColor\"\n"
+               "OpName %BP_color \"color\"\n"
+               "OpName %BP_gl_VertexIndex \"gl_VertexIndex\"\n"
+               "OpName %BP_gl_InstanceIndex \"gl_InstanceIndex\"\n"
+               "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_gl_PerVertex Block\n"
+               "OpDecorate %BP_position Location 0\n"
+               "OpDecorate %BP_vtx_color Location 1\n"
+               "OpDecorate %BP_color Location 1\n"
+               "OpDecorate %BP_gl_VertexIndex BuiltIn VertexIndex\n"
+               "OpDecorate %BP_gl_InstanceIndex BuiltIn InstanceIndex\n"
+               "${IF_decoration:opt}\n"
+               "${decoration:opt}\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_op_gl_PerVertex = OpTypePointer Output %BP_gl_PerVertex\n"
+               "%BP_stream = OpVariable %BP_op_gl_PerVertex Output\n"
+               "%BP_position = OpVariable %ip_v4f32 Input\n"
+               "%BP_vtx_color = OpVariable %op_v4f32 Output\n"
+               "%BP_color = OpVariable %ip_v4f32 Input\n"
+               "%BP_gl_VertexIndex = OpVariable %ip_i32 Input\n"
+               "%BP_gl_InstanceIndex = OpVariable %ip_i32 Input\n"
+               "${pre_main:opt}\n"
+               "${IF_variable:opt}\n"
+               "%main = OpFunction %void None %fun\n"
+               "%BP_label = OpLabel\n"
+               "${IF_carryforward:opt}\n"
+               "%BP_pos = OpLoad %v4f32 %BP_position\n"
+               "%BP_gl_pos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
+               "OpStore %BP_gl_pos %BP_pos\n"
+               "%BP_col = OpLoad %v4f32 %BP_color\n"
+               "%BP_col_transformed = OpFunctionCall %v4f32 %test_code %BP_col\n"
+               "OpStore %BP_vtx_color %BP_col_transformed\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+               "${interface_op_func:opt}\n"
+
+               "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
+               "%getId_label = OpLabel\n"
+               "%vert_id = OpLoad %i32 %BP_gl_VertexIndex\n"
+               "%is_id_0 = OpIEqual %bool %vert_id %c_i32_0\n"
+               "OpReturnValue %is_id_0\n"
+               "OpFunctionEnd\n"
+
+               "${testfun}\n";
+       return tcu::StringTemplate(vertexShaderBoilerplate).specialize(fragments);
+}
+
+// Creates tess-control-shader assembly by specializing a boilerplate
+// StringTemplate on fragments, which must (at least) map "testfun" to an
+// OpFunction definition for %test_code that takes and returns a %v4f32.
+// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
+//
+// It roughly corresponds to the following GLSL.
+//
+// #version 450
+// layout(vertices = 3) out;
+// layout(location = 1) in vec4 in_color[];
+// layout(location = 1) out vec4 out_color[];
+//
+// void main() {
+//   out_color[gl_InvocationID] = testfun(in_color[gl_InvocationID]);
+//   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
+//   if (gl_InvocationID == 0) {
+//     gl_TessLevelOuter[0] = 1.0;
+//     gl_TessLevelOuter[1] = 1.0;
+//     gl_TessLevelOuter[2] = 1.0;
+//     gl_TessLevelInner[0] = 1.0;
+//   }
+// }
+string makeTessControlShaderAssembly (const map<string, string>& fragments)
+{
+       static const char tessControlShaderBoilerplate[] =
+               "OpCapability Tessellation\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\n"
+               "${capability:opt}\n"
+               "${extension:opt}\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint TessellationControl %BP_main \"main\" %BP_out_color %BP_gl_InvocationID %BP_in_color %BP_gl_out %BP_gl_in %BP_gl_TessLevelOuter %BP_gl_TessLevelInner ${IF_entrypoint:opt} \n"
+               "OpExecutionMode %BP_main OutputVertices 3\n"
+               "${debug:opt}\n"
+               "OpName %BP_main \"main\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+               "OpName %BP_out_color \"out_color\"\n"
+               "OpName %BP_gl_InvocationID \"gl_InvocationID\"\n"
+               "OpName %BP_in_color \"in_color\"\n"
+               "OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
+               "OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
+               "OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
+               "OpName %BP_gl_out \"gl_out\"\n"
+               "OpName %BP_gl_PVOut \"gl_PerVertex\"\n"
+               "OpMemberName %BP_gl_PVOut 0 \"gl_Position\"\n"
+               "OpMemberName %BP_gl_PVOut 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_gl_PVOut 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_gl_PVOut 3 \"gl_CullDistance\"\n"
+               "OpName %BP_gl_in \"gl_in\"\n"
+               "OpName %BP_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
+               "OpName %BP_gl_TessLevelInner \"gl_TessLevelInner\"\n"
+               "OpDecorate %BP_out_color Location 1\n"
+               "OpDecorate %BP_gl_InvocationID BuiltIn InvocationId\n"
+               "OpDecorate %BP_in_color Location 1\n"
+               "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_gl_PerVertex Block\n"
+               "OpMemberDecorate %BP_gl_PVOut 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_gl_PVOut 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_gl_PVOut 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_gl_PVOut 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_gl_PVOut Block\n"
+               "OpDecorate %BP_gl_TessLevelOuter Patch\n"
+               "OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
+               "OpDecorate %BP_gl_TessLevelInner Patch\n"
+               "OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
+               "${IF_decoration:opt}\n"
+               "${decoration:opt}\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%BP_out_color = OpVariable %op_a3v4f32 Output\n"
+               "%BP_gl_InvocationID = OpVariable %ip_i32 Input\n"
+               "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
+               "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_a3_gl_PerVertex = OpTypeArray %BP_gl_PerVertex %c_u32_3\n"
+               "%BP_op_a3_gl_PerVertex = OpTypePointer Output %BP_a3_gl_PerVertex\n"
+               "%BP_gl_out = OpVariable %BP_op_a3_gl_PerVertex Output\n"
+               "%BP_gl_PVOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_a32_gl_PVOut = OpTypeArray %BP_gl_PVOut %c_u32_32\n"
+               "%BP_ip_a32_gl_PVOut = OpTypePointer Input %BP_a32_gl_PVOut\n"
+               "%BP_gl_in = OpVariable %BP_ip_a32_gl_PVOut Input\n"
+               "%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
+               "%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
+               "${pre_main:opt}\n"
+               "${IF_variable:opt}\n"
+
+               "%BP_main = OpFunction %void None %fun\n"
+               "%BP_label = OpLabel\n"
+               "%BP_gl_Invoc = OpLoad %i32 %BP_gl_InvocationID\n"
+               "${IF_carryforward:opt}\n"
+               "%BP_in_col_loc = OpAccessChain %ip_v4f32 %BP_in_color %BP_gl_Invoc\n"
+               "%BP_out_col_loc = OpAccessChain %op_v4f32 %BP_out_color %BP_gl_Invoc\n"
+               "%BP_in_col_val = OpLoad %v4f32 %BP_in_col_loc\n"
+               "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_in_col_val\n"
+               "OpStore %BP_out_col_loc %BP_clr_transformed\n"
+
+               "%BP_in_pos_loc = OpAccessChain %ip_v4f32 %BP_gl_in %BP_gl_Invoc %c_i32_0\n"
+               "%BP_out_pos_loc = OpAccessChain %op_v4f32 %BP_gl_out %BP_gl_Invoc %c_i32_0\n"
+               "%BP_in_pos_val = OpLoad %v4f32 %BP_in_pos_loc\n"
+               "OpStore %BP_out_pos_loc %BP_in_pos_val\n"
+
+               "%BP_cmp = OpIEqual %bool %BP_gl_Invoc %c_i32_0\n"
+               "OpSelectionMerge %BP_merge_label None\n"
+               "OpBranchConditional %BP_cmp %BP_if_label %BP_merge_label\n"
+               "%BP_if_label = OpLabel\n"
+               "%BP_gl_TessLevelOuterPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_0\n"
+               "%BP_gl_TessLevelOuterPos_1 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_1\n"
+               "%BP_gl_TessLevelOuterPos_2 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_2\n"
+               "%BP_gl_TessLevelInnerPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelInner %c_i32_0\n"
+               "OpStore %BP_gl_TessLevelOuterPos_0 %c_f32_1\n"
+               "OpStore %BP_gl_TessLevelOuterPos_1 %c_f32_1\n"
+               "OpStore %BP_gl_TessLevelOuterPos_2 %c_f32_1\n"
+               "OpStore %BP_gl_TessLevelInnerPos_0 %c_f32_1\n"
+               "OpBranch %BP_merge_label\n"
+               "%BP_merge_label = OpLabel\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+               "${interface_op_func:opt}\n"
+
+               "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
+               "%getId_label = OpLabel\n"
+               "%invocation_id = OpLoad %i32 %BP_gl_InvocationID\n"
+               "%is_id_0 = OpIEqual %bool %invocation_id %c_i32_0\n"
+               "OpReturnValue %is_id_0\n"
+               "OpFunctionEnd\n"
+
+               "${testfun}\n";
+       return tcu::StringTemplate(tessControlShaderBoilerplate).specialize(fragments);
+}
+
+// Creates tess-evaluation-shader assembly by specializing a boilerplate
+// StringTemplate on fragments, which must (at least) map "testfun" to an
+// OpFunction definition for %test_code that takes and returns a %v4f32.
+// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
+//
+// It roughly corresponds to the following glsl.
+//
+// #version 450
+//
+// layout(triangles, equal_spacing, ccw) in;
+// layout(location = 1) in vec4 in_color[];
+// layout(location = 1) out vec4 out_color;
+//
+// #define interpolate(val)
+//   vec4(gl_TessCoord.x) * val[0] + vec4(gl_TessCoord.y) * val[1] +
+//          vec4(gl_TessCoord.z) * val[2]
+//
+// void main() {
+//   gl_Position = vec4(gl_TessCoord.x) * gl_in[0].gl_Position +
+//                  vec4(gl_TessCoord.y) * gl_in[1].gl_Position +
+//                  vec4(gl_TessCoord.z) * gl_in[2].gl_Position;
+//   out_color = testfun(interpolate(in_color));
+// }
+string makeTessEvalShaderAssembly(const map<string, string>& fragments)
+{
+       static const char tessEvalBoilerplate[] =
+               "OpCapability Tessellation\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\n"
+               "${capability:opt}\n"
+               "${extension:opt}\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint TessellationEvaluation %BP_main \"main\" %BP_stream %BP_gl_TessCoord %BP_gl_PrimitiveID %BP_gl_in %BP_out_color %BP_in_color ${IF_entrypoint:opt} \n"
+               "OpExecutionMode %BP_main Triangles\n"
+               "OpExecutionMode %BP_main SpacingEqual\n"
+               "OpExecutionMode %BP_main VertexOrderCcw\n"
+               "${debug:opt}\n"
+               "OpName %BP_main \"main\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+               "OpName %BP_gl_PerVertexOut \"gl_PerVertex\"\n"
+               "OpMemberName %BP_gl_PerVertexOut 0 \"gl_Position\"\n"
+               "OpMemberName %BP_gl_PerVertexOut 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_gl_PerVertexOut 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_gl_PerVertexOut 3 \"gl_CullDistance\"\n"
+               "OpName %BP_stream \"\"\n"
+               "OpName %BP_gl_TessCoord \"gl_TessCoord\"\n"
+               "OpName %BP_gl_PerVertexIn \"gl_PerVertex\"\n"
+               "OpName %BP_gl_PrimitiveID \"gl_PrimitiveID\"\n"
+               "OpMemberName %BP_gl_PerVertexIn 0 \"gl_Position\"\n"
+               "OpMemberName %BP_gl_PerVertexIn 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_gl_PerVertexIn 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_gl_PerVertexIn 3 \"gl_CullDistance\"\n"
+               "OpName %BP_gl_in \"gl_in\"\n"
+               "OpName %BP_out_color \"out_color\"\n"
+               "OpName %BP_in_color \"in_color\"\n"
+               "OpMemberDecorate %BP_gl_PerVertexOut 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_gl_PerVertexOut 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_gl_PerVertexOut 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_gl_PerVertexOut 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_gl_PerVertexOut Block\n"
+               "OpDecorate %BP_gl_PrimitiveID BuiltIn PrimitiveId\n"
+               "OpDecorate %BP_gl_TessCoord BuiltIn TessCoord\n"
+               "OpMemberDecorate %BP_gl_PerVertexIn 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_gl_PerVertexIn 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_gl_PerVertexIn 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_gl_PerVertexIn 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_gl_PerVertexIn Block\n"
+               "OpDecorate %BP_out_color Location 1\n"
+               "OpDecorate %BP_in_color Location 1\n"
+               "${IF_decoration:opt}\n"
+               "${decoration:opt}\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%BP_gl_PerVertexOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_op_gl_PerVertexOut = OpTypePointer Output %BP_gl_PerVertexOut\n"
+               "%BP_stream = OpVariable %BP_op_gl_PerVertexOut Output\n"
+               "%BP_gl_TessCoord = OpVariable %ip_v3f32 Input\n"
+               "%BP_gl_PrimitiveID = OpVariable %op_i32 Input\n"
+               "%BP_gl_PerVertexIn = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_a32_gl_PerVertexIn = OpTypeArray %BP_gl_PerVertexIn %c_u32_32\n"
+               "%BP_ip_a32_gl_PerVertexIn = OpTypePointer Input %BP_a32_gl_PerVertexIn\n"
+               "%BP_gl_in = OpVariable %BP_ip_a32_gl_PerVertexIn Input\n"
+               "%BP_out_color = OpVariable %op_v4f32 Output\n"
+               "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
+               "${pre_main:opt}\n"
+               "${IF_variable:opt}\n"
+               "%BP_main = OpFunction %void None %fun\n"
+               "%BP_label = OpLabel\n"
+               "${IF_carryforward:opt}\n"
+               "%BP_gl_TC_0 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_0\n"
+               "%BP_gl_TC_1 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_1\n"
+               "%BP_gl_TC_2 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_2\n"
+               "%BP_gl_in_gl_Pos_0 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
+               "%BP_gl_in_gl_Pos_1 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
+               "%BP_gl_in_gl_Pos_2 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
+
+               "%BP_gl_OPos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
+               "%BP_in_color_0 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
+               "%BP_in_color_1 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
+               "%BP_in_color_2 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
+
+               "%BP_TC_W_0 = OpLoad %f32 %BP_gl_TC_0\n"
+               "%BP_TC_W_1 = OpLoad %f32 %BP_gl_TC_1\n"
+               "%BP_TC_W_2 = OpLoad %f32 %BP_gl_TC_2\n"
+               "%BP_v4f32_TC_0 = OpCompositeConstruct %v4f32 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0\n"
+               "%BP_v4f32_TC_1 = OpCompositeConstruct %v4f32 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1\n"
+               "%BP_v4f32_TC_2 = OpCompositeConstruct %v4f32 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2\n"
+
+               "%BP_gl_IP_0 = OpLoad %v4f32 %BP_gl_in_gl_Pos_0\n"
+               "%BP_gl_IP_1 = OpLoad %v4f32 %BP_gl_in_gl_Pos_1\n"
+               "%BP_gl_IP_2 = OpLoad %v4f32 %BP_gl_in_gl_Pos_2\n"
+
+               "%BP_IP_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_gl_IP_0\n"
+               "%BP_IP_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_gl_IP_1\n"
+               "%BP_IP_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_gl_IP_2\n"
+
+               "%BP_pos_sum_0 = OpFAdd %v4f32 %BP_IP_W_0 %BP_IP_W_1\n"
+               "%BP_pos_sum_1 = OpFAdd %v4f32 %BP_pos_sum_0 %BP_IP_W_2\n"
+
+               "OpStore %BP_gl_OPos %BP_pos_sum_1\n"
+
+               "%BP_IC_0 = OpLoad %v4f32 %BP_in_color_0\n"
+               "%BP_IC_1 = OpLoad %v4f32 %BP_in_color_1\n"
+               "%BP_IC_2 = OpLoad %v4f32 %BP_in_color_2\n"
+
+               "%BP_IC_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_IC_0\n"
+               "%BP_IC_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_IC_1\n"
+               "%BP_IC_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_IC_2\n"
+
+               "%BP_col_sum_0 = OpFAdd %v4f32 %BP_IC_W_0 %BP_IC_W_1\n"
+               "%BP_col_sum_1 = OpFAdd %v4f32 %BP_col_sum_0 %BP_IC_W_2\n"
+
+               "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_col_sum_1\n"
+
+               "OpStore %BP_out_color %BP_clr_transformed\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+               "${interface_op_func:opt}\n"
+
+               "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
+               "%getId_label = OpLabel\n"
+               "%primitive_id = OpLoad %i32 %BP_gl_PrimitiveID\n"
+               "%is_id_0 = OpIEqual %bool %primitive_id %c_i32_0\n"
+               "OpReturnValue %is_id_0\n"
+               "OpFunctionEnd\n"
+
+               "${testfun}\n";
+       return tcu::StringTemplate(tessEvalBoilerplate).specialize(fragments);
+}
+
+// Creates geometry-shader assembly by specializing a boilerplate StringTemplate
+// on fragments, which must (at least) map "testfun" to an OpFunction definition
+// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
+// with "BP_" to avoid collisions with fragments.
+//
+// Derived from this GLSL:
+//
+// #version 450
+// layout(triangles) in;
+// layout(triangle_strip, max_vertices = 3) out;
+//
+// layout(location = 1) in vec4 in_color[];
+// layout(location = 1) out vec4 out_color;
+//
+// void main() {
+//   gl_Position = gl_in[0].gl_Position;
+//   out_color = test_fun(in_color[0]);
+//   EmitVertex();
+//   gl_Position = gl_in[1].gl_Position;
+//   out_color = test_fun(in_color[1]);
+//   EmitVertex();
+//   gl_Position = gl_in[2].gl_Position;
+//   out_color = test_fun(in_color[2]);
+//   EmitVertex();
+//   EndPrimitive();
+// }
+string makeGeometryShaderAssembly(const map<string, string>& fragments)
+{
+       static const char geometryShaderBoilerplate[] =
+               "OpCapability Geometry\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\n"
+               "${capability:opt}\n"
+               "${extension:opt}\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Geometry %BP_main \"main\" %BP_out_gl_position %BP_gl_PrimitiveID %BP_gl_in %BP_out_color %BP_in_color ${IF_entrypoint:opt} \n"
+               "OpExecutionMode %BP_main Triangles\n"
+               "OpExecutionMode %BP_main OutputTriangleStrip\n"
+               "OpExecutionMode %BP_main OutputVertices 3\n"
+               "${debug:opt}\n"
+               "OpName %BP_main \"main\"\n"
+               "OpName %BP_gl_PrimitiveID \"gl_PrimitiveID\"\n"
+               "OpName %BP_per_vertex_in \"gl_PerVertex\"\n"
+               "OpMemberName %BP_per_vertex_in 0 \"gl_Position\"\n"
+               "OpMemberName %BP_per_vertex_in 1 \"gl_PointSize\"\n"
+               "OpMemberName %BP_per_vertex_in 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %BP_per_vertex_in 3 \"gl_CullDistance\"\n"
+               "OpName %BP_gl_in \"gl_in\"\n"
+               "OpName %BP_out_color \"out_color\"\n"
+               "OpName %BP_in_color \"in_color\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+               "OpDecorate %BP_gl_PrimitiveID BuiltIn PrimitiveId\n"
+               "OpDecorate %BP_out_gl_position BuiltIn Position\n"
+               "OpMemberDecorate %BP_per_vertex_in 0 BuiltIn Position\n"
+               "OpMemberDecorate %BP_per_vertex_in 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %BP_per_vertex_in 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %BP_per_vertex_in 3 BuiltIn CullDistance\n"
+               "OpDecorate %BP_per_vertex_in Block\n"
+               "OpDecorate %BP_out_color Location 1\n"
+               "OpDecorate %BP_in_color Location 1\n"
+               "${IF_decoration:opt}\n"
+               "${decoration:opt}\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%BP_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
+               "%BP_a3_per_vertex_in = OpTypeArray %BP_per_vertex_in %c_u32_3\n"
+               "%BP_ip_a3_per_vertex_in = OpTypePointer Input %BP_a3_per_vertex_in\n"
+
+               "%BP_gl_in = OpVariable %BP_ip_a3_per_vertex_in Input\n"
+               "%BP_out_color = OpVariable %op_v4f32 Output\n"
+               "%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
+               "%BP_gl_PrimitiveID = OpVariable %ip_i32 Input\n"
+               "%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
+               "${pre_main:opt}\n"
+               "${IF_variable:opt}\n"
+
+               "%BP_main = OpFunction %void None %fun\n"
+               "%BP_label = OpLabel\n"
+
+               "${IF_carryforward:opt}\n"
+
+               "%BP_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
+               "%BP_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
+               "%BP_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
+
+               "%BP_in_position_0 = OpLoad %v4f32 %BP_gl_in_0_gl_position\n"
+               "%BP_in_position_1 = OpLoad %v4f32 %BP_gl_in_1_gl_position\n"
+               "%BP_in_position_2 = OpLoad %v4f32 %BP_gl_in_2_gl_position \n"
+
+               "%BP_in_color_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
+               "%BP_in_color_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
+               "%BP_in_color_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
+
+               "%BP_in_color_0 = OpLoad %v4f32 %BP_in_color_0_ptr\n"
+               "%BP_in_color_1 = OpLoad %v4f32 %BP_in_color_1_ptr\n"
+               "%BP_in_color_2 = OpLoad %v4f32 %BP_in_color_2_ptr\n"
+
+               "%BP_transformed_in_color_0 = OpFunctionCall %v4f32 %test_code %BP_in_color_0\n"
+               "%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"
+
+               "OpStore %BP_out_gl_position %BP_in_position_1\n"
+               "OpStore %BP_out_color %BP_transformed_in_color_1\n"
+               "OpEmitVertex\n"
+
+               "OpStore %BP_out_gl_position %BP_in_position_2\n"
+               "OpStore %BP_out_color %BP_transformed_in_color_2\n"
+               "OpEmitVertex\n"
+
+               "OpEndPrimitive\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+               "${interface_op_func:opt}\n"
+
+               "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
+               "%getId_label = OpLabel\n"
+               "%primitive_id = OpLoad %i32 %BP_gl_PrimitiveID\n"
+               "%is_id_0 = OpIEqual %bool %primitive_id %c_i32_0\n"
+               "OpReturnValue %is_id_0\n"
+               "OpFunctionEnd\n"
+
+               "${testfun}\n";
+       return tcu::StringTemplate(geometryShaderBoilerplate).specialize(fragments);
+}
+
+// Creates fragment-shader assembly by specializing a boilerplate StringTemplate
+// on fragments, which must (at least) map "testfun" to an OpFunction definition
+// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
+// with "BP_" to avoid collisions with fragments.
+//
+// Derived from this GLSL:
+//
+// layout(location = 1) in highp vec4 vtxColor;
+// layout(location = 0) out highp vec4 fragColor;
+// highp vec4 testfun(highp vec4 x) { return x; }
+// void main(void) { fragColor = testfun(vtxColor); }
+//
+// with modifications including passing vtxColor by value and ripping out
+// testfun() definition.
+string makeFragmentShaderAssembly(const map<string, string>& fragments)
+{
+       static const char fragmentShaderBoilerplate[] =
+               "OpCapability Shader\n"
+               "${capability:opt}\n"
+               "${extension:opt}\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint Fragment %BP_main \"main\" %BP_vtxColor %BP_fragColor %BP_gl_FragCoord ${IF_entrypoint:opt} \n"
+               "OpExecutionMode %BP_main OriginUpperLeft\n"
+               "${debug:opt}\n"
+               "OpName %BP_main \"main\"\n"
+               "OpName %BP_gl_FragCoord \"fragCoord\"\n"
+               "OpName %BP_fragColor \"fragColor\"\n"
+               "OpName %BP_vtxColor \"vtxColor\"\n"
+               "OpName %test_code \"testfun(vf4;\"\n"
+               "OpDecorate %BP_fragColor Location 0\n"
+               "OpDecorate %BP_vtxColor Location 1\n"
+               "OpDecorate %BP_gl_FragCoord BuiltIn FragCoord\n"
+               "${IF_decoration:opt}\n"
+               "${decoration:opt}\n"
+               SPIRV_ASSEMBLY_TYPES
+               SPIRV_ASSEMBLY_CONSTANTS
+               SPIRV_ASSEMBLY_ARRAYS
+               "%BP_gl_FragCoord = OpVariable %ip_v4f32 Input\n"
+               "%BP_fragColor = OpVariable %op_v4f32 Output\n"
+               "%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
+               "${pre_main:opt}\n"
+               "${IF_variable:opt}\n"
+               "%BP_main = OpFunction %void None %fun\n"
+               "%BP_label_main = OpLabel\n"
+               "${IF_carryforward:opt}\n"
+               "%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
+               "%BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1\n"
+               "OpStore %BP_fragColor %BP_tmp2\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n"
+               "${interface_op_func:opt}\n"
+
+               "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
+               "%getId_label = OpLabel\n"
+               "%loc_x_coord = OpAccessChain %ip_f32 %BP_gl_FragCoord %c_i32_0\n"
+               "%loc_y_coord = OpAccessChain %ip_f32 %BP_gl_FragCoord %c_i32_1\n"
+               "%x_coord = OpLoad %f32 %loc_x_coord\n"
+               "%y_coord = OpLoad %f32 %loc_y_coord\n"
+               "%is_x_idx0 = OpFOrdEqual %bool %x_coord %c_f32_0_5\n"
+               "%is_y_idx0 = OpFOrdEqual %bool %y_coord %c_f32_0_5\n"
+               "%is_frag_0 = OpLogicalAnd %bool %is_x_idx0 %is_y_idx0\n"
+               "OpReturnValue %is_frag_0\n"
+               "OpFunctionEnd\n"
+
+               "${testfun}\n";
+       return tcu::StringTemplate(fragmentShaderBoilerplate).specialize(fragments);
+}
+
+// Creates mappings from placeholders to pass-through shader code which copies
+// the input to the output faithfully.
+map<string, string> passthruInterface(const IFDataType& data_type)
+{
+       const string            var_type        = data_type.str();
+       map<string, string>     fragments       = passthruFragments();
+       const string            functype        = string("%") + var_type + "_" + var_type + "_function";
+
+       fragments["interface_op_func"]  =
+               string("%interface_op_func = OpFunction %") + var_type + " None " + functype + "\n"
+               "               %io_param1 = OpFunctionParameter %" + var_type + "\n"
+               "                %IF_label = OpLabel\n"
+               "                            OpReturnValue %io_param1\n"
+               "                            OpFunctionEnd\n";
+       fragments["input_type"]                 = var_type;
+       fragments["output_type"]                = var_type;
+       fragments["pre_main"]                   = "";
+
+       if (!data_type.elementIs32bit())
+       {
+               if (data_type.elementType == NUMBERTYPE_FLOAT16)
+               {
+                       fragments["pre_main"]   += "%f16 = OpTypeFloat 16\n";
+               }
+               else if (data_type.elementType == NUMBERTYPE_INT16)
+               {
+                       fragments["pre_main"]   += "%i16 = OpTypeInt 16 1\n";
+               }
+               else
+               {
+                       fragments["pre_main"]   += "%u16 = OpTypeInt 16 0\n";
+               }
+
+               fragments["capability"]         = "OpCapability StorageInputOutput16\n";
+
+               if (data_type.isVector())
+               {
+                       fragments["pre_main"]   += "%" + var_type + " = OpTypeVector %" + IFDataType(1, data_type.elementType).str() + " " + numberToString(data_type.numElements) + "\n";
+               }
+
+               fragments["pre_main"]           +=
+                       "%ip_" + var_type + " = OpTypePointer Input %" + var_type + "\n"
+                       "%op_" + var_type + " = OpTypePointer Output %" + var_type + "\n";
+       }
+
+       fragments["pre_main"]                   +=
+               functype + " = OpTypeFunction %" + var_type + " %" + var_type + "\n"
+               "%a3" + var_type + " = OpTypeArray %" + var_type + " %c_i32_3\n"
+               "%ip_a3" + var_type + " = OpTypePointer Input %a3" + var_type + "\n"
+               "%op_a3" + var_type + " = OpTypePointer Output %a3" + var_type + "\n";
+
+       return fragments;
+}
+
+// Returns mappings from interface placeholders to their concrete values.
+//
+// The concrete values should be specialized again to provide ${input_type}
+// and ${output_type}.
+//
+// %ip_${input_type} and %op_${output_type} should also be defined in the final code.
+map<string, string> fillInterfacePlaceholderVert (void)
+{
+       map<string, string>     fragments       ;
+
+       fragments["IF_entrypoint"]              = "%IF_input %IF_output";
+       fragments["IF_variable"]                =
+               " %IF_input = OpVariable %ip_${input_type} Input\n"
+               "%IF_output = OpVariable %op_${output_type} Output\n";
+       fragments["IF_decoration"]              =
+               "OpDecorate  %IF_input Location 2\n"
+               "OpDecorate %IF_output Location 2\n";
+       fragments["IF_carryforward"]    =
+               "%IF_input_val = OpLoad %${input_type} %IF_input\n"
+               "   %IF_result = OpFunctionCall %${output_type} %interface_op_func %IF_input_val\n"
+               "                OpStore %IF_output %IF_result\n";
+
+       // Make sure the rest still need to be instantialized.
+       fragments["capability"]                 = "${capability:opt}";
+       fragments["extension"]                  = "${extension:opt}";
+       fragments["debug"]                              = "${debug:opt}";
+       fragments["decoration"]                 = "${decoration:opt}";
+       fragments["pre_main"]                   = "${pre_main:opt}";
+       fragments["testfun"]                    = "${testfun}";
+       fragments["interface_op_func"]  = "${interface_op_func}";
+
+       return fragments;
+}
+
+// Returns mappings from interface placeholders to their concrete values.
+//
+// The concrete values should be specialized again to provide ${input_type}
+// and ${output_type}.
+//
+// %ip_${input_type} and %op_${output_type} should also be defined in the final code.
+map<string, string> fillInterfacePlaceholderFrag (void)
+{
+       map<string, string>     fragments       ;
+
+       fragments["IF_entrypoint"]              = "%IF_input %IF_output";
+       fragments["IF_variable"]                =
+               " %IF_input = OpVariable %ip_${input_type} Input\n"
+               "%IF_output = OpVariable %op_${output_type} Output\n";
+       fragments["IF_decoration"]              =
+               "OpDecorate  %IF_input Location 2\n"
+               "OpDecorate %IF_output Location 1\n";  // Fragment shader should write to location #1.
+       fragments["IF_carryforward"]    =
+               "%IF_input_val = OpLoad %${input_type} %IF_input\n"
+               "   %IF_result = OpFunctionCall %${output_type} %interface_op_func %IF_input_val\n"
+               "                OpStore %IF_output %IF_result\n";
+
+       // Make sure the rest still need to be instantialized.
+       fragments["capability"]                 = "${capability:opt}";
+       fragments["extension"]                  = "${extension:opt}";
+       fragments["debug"]                              = "${debug:opt}";
+       fragments["decoration"]                 = "${decoration:opt}";
+       fragments["pre_main"]                   = "${pre_main:opt}";
+       fragments["testfun"]                    = "${testfun}";
+       fragments["interface_op_func"]  = "${interface_op_func}";
+
+       return fragments;
+}
+
+// Returns mappings from interface placeholders to their concrete values.
+//
+// The concrete values should be specialized again to provide ${input_type}
+// and ${output_type}.
+//
+// %ip_${input_type}, %op_${output_type}, %ip_a3${input_type}, and $op_a3${output_type}
+// should also be defined in the final code.
+map<string, string> fillInterfacePlaceholderTessCtrl (void)
+{
+       map<string, string>     fragments       ;
+
+       fragments["IF_entrypoint"]              = "%IF_input %IF_output";
+       fragments["IF_variable"]                =
+               " %IF_input = OpVariable %ip_a3${input_type} Input\n"
+               "%IF_output = OpVariable %op_a3${output_type} Output\n";
+       fragments["IF_decoration"]              =
+               "OpDecorate  %IF_input Location 2\n"
+               "OpDecorate %IF_output Location 2\n";
+       fragments["IF_carryforward"]    =
+               " %IF_input_ptr0 = OpAccessChain %ip_${input_type} %IF_input %c_i32_0\n"
+               " %IF_input_ptr1 = OpAccessChain %ip_${input_type} %IF_input %c_i32_1\n"
+               " %IF_input_ptr2 = OpAccessChain %ip_${input_type} %IF_input %c_i32_2\n"
+               "%IF_output_ptr0 = OpAccessChain %op_${output_type} %IF_output %c_i32_0\n"
+               "%IF_output_ptr1 = OpAccessChain %op_${output_type} %IF_output %c_i32_1\n"
+               "%IF_output_ptr2 = OpAccessChain %op_${output_type} %IF_output %c_i32_2\n"
+               "%IF_input_val0 = OpLoad %${input_type} %IF_input_ptr0\n"
+               "%IF_input_val1 = OpLoad %${input_type} %IF_input_ptr1\n"
+               "%IF_input_val2 = OpLoad %${input_type} %IF_input_ptr2\n"
+               "%IF_input_res0 = OpFunctionCall %${output_type} %interface_op_func %IF_input_val0\n"
+               "%IF_input_res1 = OpFunctionCall %${output_type} %interface_op_func %IF_input_val1\n"
+               "%IF_input_res2 = OpFunctionCall %${output_type} %interface_op_func %IF_input_val2\n"
+               "OpStore %IF_output_ptr0 %IF_input_res0\n"
+               "OpStore %IF_output_ptr1 %IF_input_res1\n"
+               "OpStore %IF_output_ptr2 %IF_input_res2\n";
+
+       // Make sure the rest still need to be instantialized.
+       fragments["capability"]                 = "${capability:opt}";
+       fragments["extension"]                  = "${extension:opt}";
+       fragments["debug"]                              = "${debug:opt}";
+       fragments["decoration"]                 = "${decoration:opt}";
+       fragments["pre_main"]                   = "${pre_main:opt}";
+       fragments["testfun"]                    = "${testfun}";
+       fragments["interface_op_func"]  = "${interface_op_func}";
+
+       return fragments;
+}
+
+// Returns mappings from interface placeholders to their concrete values.
+//
+// The concrete values should be specialized again to provide ${input_type}
+// and ${output_type}.
+//
+// %ip_${input_type}, %op_${output_type}, %ip_a3${input_type}, and $op_a3${output_type}
+// should also be defined in the final code.
+map<string, string> fillInterfacePlaceholderTessEvalGeom (void)
+{
+       map<string, string>     fragments       ;
+
+       fragments["IF_entrypoint"]              = "%IF_input %IF_output";
+       fragments["IF_variable"]                =
+               " %IF_input = OpVariable %ip_a3${input_type} Input\n"
+               "%IF_output = OpVariable %op_${output_type} Output\n";
+       fragments["IF_decoration"]              =
+               "OpDecorate  %IF_input Location 2\n"
+               "OpDecorate %IF_output Location 2\n";
+       fragments["IF_carryforward"]    =
+               // Only get the first value since all three values are the same anyway.
+               " %IF_input_ptr0 = OpAccessChain %ip_${input_type} %IF_input %c_i32_0\n"
+               " %IF_input_val0 = OpLoad %${input_type} %IF_input_ptr0\n"
+               " %IF_input_res0 = OpFunctionCall %${output_type} %interface_op_func %IF_input_val0\n"
+               "OpStore %IF_output %IF_input_res0\n";
+
+       // Make sure the rest still need to be instantialized.
+       fragments["capability"]                 = "${capability:opt}";
+       fragments["extension"]                  = "${extension:opt}";
+       fragments["debug"]                              = "${debug:opt}";
+       fragments["decoration"]                 = "${decoration:opt}";
+       fragments["pre_main"]                   = "${pre_main:opt}";
+       fragments["testfun"]                    = "${testfun}";
+       fragments["interface_op_func"]  = "${interface_op_func}";
+
+       return fragments;
+}
+
+map<string, string> passthruFragments(void)
+{
+       map<string, string> fragments;
+       fragments["testfun"] =
+               // A %test_code function that returns its argument unchanged.
+               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
+               "%param1 = OpFunctionParameter %v4f32\n"
+               "%label_testfun = OpLabel\n"
+               "OpReturnValue %param1\n"
+               "OpFunctionEnd\n";
+       return fragments;
+}
+
+// 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)
+{
+       if (!context.interfaces.empty())
+       {
+               // Inject boilerplate code to wire up additional input/output variables between stages.
+               // Just copy the contents in input variable to output variable in all stages except
+               // the customized stage.
+               dst.spirvAsmSources.add("vert") << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert())).specialize(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag())).specialize(passthruInterface(context.interfaces.getOutputType()));
+       } else {
+               map<string, string> passthru = passthruFragments();
+
+               dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
+       }
+}
+
+// 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)
+{
+       if (!context.interfaces.empty())
+       {
+               // Inject boilerplate code to wire up additional input/output variables between stages.
+               // Just copy the contents in input variable to output variable in all stages except
+               // the customized stage.
+               dst.spirvAsmSources.add("vert") << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert())).specialize(passthruInterface(context.interfaces.getInputType()));
+               dst.spirvAsmSources.add("tessc") << StringTemplate(makeTessControlShaderAssembly(fillInterfacePlaceholderTessCtrl())).specialize(context.testCodeFragments);
+               dst.spirvAsmSources.add("tesse") << StringTemplate(makeTessEvalShaderAssembly(fillInterfacePlaceholderTessEvalGeom())).specialize(passthruInterface(context.interfaces.getOutputType()));
+               dst.spirvAsmSources.add("frag") << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag())).specialize(passthruInterface(context.interfaces.getOutputType()));
+       }
+       else
+       {
+               map<string, string> passthru = passthruFragments();
+
+               dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
+               dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
+               dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
+               dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
+       }
+}
+
+// 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)
+{
+       if (!context.interfaces.empty())
+       {
+               // Inject boilerplate code to wire up additional input/output variables between stages.
+               // Just copy the contents in input variable to output variable in all stages except
+               // the customized stage.
+               dst.spirvAsmSources.add("vert") << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert())).specialize(passthruInterface(context.interfaces.getInputType()));
+               dst.spirvAsmSources.add("tessc") << StringTemplate(makeTessControlShaderAssembly(fillInterfacePlaceholderTessCtrl())).specialize(passthruInterface(context.interfaces.getInputType()));
+               dst.spirvAsmSources.add("tesse") << StringTemplate(makeTessEvalShaderAssembly(fillInterfacePlaceholderTessEvalGeom())).specialize(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag())).specialize(passthruInterface(context.interfaces.getOutputType()));
+       }
+       else
+       {
+               map<string, string> passthru = passthruFragments();
+               dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
+               dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
+               dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
+       }
+}
+
+// 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)
+{
+       if (!context.interfaces.empty())
+       {
+               // Inject boilerplate code to wire up additional input/output variables between stages.
+               // Just copy the contents in input variable to output variable in all stages except
+               // the customized stage.
+               dst.spirvAsmSources.add("vert") << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert())).specialize(passthruInterface(context.interfaces.getInputType()));
+               dst.spirvAsmSources.add("geom") << StringTemplate(makeGeometryShaderAssembly(fillInterfacePlaceholderTessEvalGeom())).specialize(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag())).specialize(passthruInterface(context.interfaces.getOutputType()));
+       }
+       else
+       {
+               map<string, string> passthru = passthruFragments();
+               dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
+               dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(context.testCodeFragments);
+               dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
+       }
+}
+
+// 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)
+{
+       if (!context.interfaces.empty())
+       {
+               // Inject boilerplate code to wire up additional input/output variables between stages.
+               // Just copy the contents in input variable to output variable in all stages except
+               // the customized stage.
+               dst.spirvAsmSources.add("vert") << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert())).specialize(passthruInterface(context.interfaces.getInputType()));
+               dst.spirvAsmSources.add("frag") << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag())).specialize(context.testCodeFragments);
+       }
+       else
+       {
+               map<string, string> passthru = passthruFragments();
+               dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
+               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 OpMemberName at some point
+       dst.spirvAsmSources.add("module") <<
+               "OpCapability Shader\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\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\" %geom_out_gl_position %geom_gl_in %geom_out_color %geom_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 OutputTriangleStrip\n"
+               "OpExecutionMode %geom_main OutputVertices 3\n"
+
+               "OpExecutionMode %tessc_main OutputVertices 3\n"
+
+               "OpExecutionMode %tesse_main Triangles\n"
+               "OpExecutionMode %tesse_main SpacingEqual\n"
+               "OpExecutionMode %tesse_main VertexOrderCcw\n"
+
+               "OpExecutionMode %frag_main OriginUpperLeft\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_VertexIndex\"\n"
+               "OpName %vert_instance_id \"gl_InstanceIndex\"\n"
+               "OpName %geom_main \"main\"\n"
+               "OpName %geom_per_vertex_in \"gl_PerVertex\"\n"
+               "OpMemberName %geom_per_vertex_in 0 \"gl_Position\"\n"
+               "OpMemberName %geom_per_vertex_in 1 \"gl_PointSize\"\n"
+               "OpMemberName %geom_per_vertex_in 2 \"gl_ClipDistance\"\n"
+               "OpMemberName %geom_per_vertex_in 3 \"gl_CullDistance\"\n"
+               "OpName %geom_gl_in \"gl_in\"\n"
+               "OpName %geom_out_color \"out_color\"\n"
+               "OpName %geom_in_color \"in_color\"\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"
+               "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"
+               "OpName %frag_main \"main\"\n"
+               "OpName %frag_fragColor \"fragColor\"\n"
+               "OpName %frag_vtxColor \"vtxColor\"\n"
+
+               "; Vertex decorations\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 VertexIndex\n"
+               "OpDecorate %vert_instance_id BuiltIn InstanceIndex\n"
+
+               "; Geometry decorations\n"
+               "OpDecorate %geom_out_gl_position BuiltIn Position\n"
+               "OpMemberDecorate %geom_per_vertex_in 0 BuiltIn Position\n"
+               "OpMemberDecorate %geom_per_vertex_in 1 BuiltIn PointSize\n"
+               "OpMemberDecorate %geom_per_vertex_in 2 BuiltIn ClipDistance\n"
+               "OpMemberDecorate %geom_per_vertex_in 3 BuiltIn CullDistance\n"
+               "OpDecorate %geom_per_vertex_in Block\n"
+               "OpDecorate %geom_out_color Location 1\n"
+               "OpDecorate %geom_in_color Location 1\n"
+
+               "; Tessellation Control decorations\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"
+               "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"
+               "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 %geom_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 %tesse_in_pos_0 %tesse_tc_0\n"
+               "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_1 %tesse_tc_1\n"
+               "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_2 %tesse_tc_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_in_clr_0 %tesse_tc_0\n"
+               "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_1 %tesse_tc_1\n"
+               "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_2 %tesse_tc_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";
+}
+
+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 \"vert1\"\n"
+               "OpName %main2 \"vert2\"\n"
+               "OpName %vtxPosition \"vtxPosition\"\n"
+               "OpName %Position \"position\"\n"
+               "OpName %vtxColor \"vtxColor\"\n"
+               "OpName %color \"color\"\n"
+               "OpName %vertex_id \"gl_VertexIndex\"\n"
+               "OpName %instance_id \"gl_InstanceIndex\"\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 VertexIndex\n"
+               "OpDecorate %instance_id BuiltIn InstanceIndex\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"
+               "%tmp_color4 = OpVectorInsertDynamic %v4f32 %tmp_color3 %c_f32_1 %c_i32_3\n"
+               "OpStore %vtxColor %tmp_color4\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"
+               "%tmp4 = OpVectorInsertDynamic %v4f32 %tmp3 %c_f32_1 %c_i32_3\n"
+               "OpStore %fragColor %tmp4\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+
+       dst.spirvAsmSources.add("geom") <<
+               "OpCapability Geometry\n"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\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 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 %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"
+               "%geom2_transformed_in_color_0_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_0 %c_f32_1 %c_i32_3\n"
+               "%geom2_transformed_in_color_1_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_1 %c_f32_1 %c_i32_3\n"
+               "%geom2_transformed_in_color_2_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_2 %c_f32_1 %c_i32_3\n"
+               "OpStore %out_gl_position %geom2_in_position_0\n"
+               "OpStore %out_color %geom2_transformed_in_color_0_a\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom2_in_position_1\n"
+               "OpStore %out_color %geom2_transformed_in_color_1_a\n"
+               "OpEmitVertex\n"
+               "OpStore %out_gl_position %geom2_in_position_2\n"
+               "OpStore %out_color %geom2_transformed_in_color_2_a\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 %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"
+               "%tessc2_transformed_color_a = OpVectorInsertDynamic %v4f32 %tessc2_transformed_color %c_f32_1 %c_i32_3\n"
+               "OpStore %tessc2_out_color_ptr %tessc2_transformed_color_a\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 %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"
+               "OpCapability ClipDistance\n"
+               "OpCapability CullDistance\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 %tesse1_main SpacingEqual\n"
+               "OpExecutionMode %tesse1_main VertexOrderCcw\n"
+               "OpExecutionMode %tesse2_main Triangles\n"
+               "OpExecutionMode %tesse2_main SpacingEqual\n"
+               "OpExecutionMode %tesse2_main VertexOrderCcw\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_in_pos_0 %tesse1_tc_0\n"
+               "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
+               "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_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_in_clr_0 %tesse1_tc_0\n"
+               "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
+               "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_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_in_pos_0 %tesse2_tc_0\n"
+               "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_1 %tesse2_tc_1\n"
+               "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_2 %tesse2_tc_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_in_clr_0 %tesse2_tc_0\n"
+               "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_1 %tesse2_tc_1\n"
+               "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_2 %tesse2_tc_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"
+               "%tesse2_clr_transformed_a = OpVectorInsertDynamic %v4f32 %tesse2_clr_transformed %c_f32_1 %c_i32_3\n"
+               "OpStore %out_color %tesse2_clr_transformed_a\n"
+               "OpReturn\n"
+               "OpFunctionEnd\n";
+}
+
+bool compare16BitFloat (float original, deUint16 returned, RoundingModeFlags flags, tcu::TestLog& log)
+{
+       // We only support RTE, RTZ, or both.
+       DE_ASSERT(static_cast<int>(flags) > 0 && static_cast<int>(flags) < 4);
+
+       const Float32   originalFloat   (original);
+       const Float16   returnedFloat   (returned);
+
+       // Zero are turned into zero under both RTE and RTZ.
+       if (originalFloat.isZero())
+       {
+               if (returnedFloat.isZero())
+                       return true;
+
+               log << TestLog::Message << "Error: expected zero but returned " << returned << TestLog::EndMessage;
+               return false;
+       }
+
+       // Inf are always turned into Inf with the same sign, too.
+       if (originalFloat.isInf())
+       {
+               if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
+                       return true;
+
+               log << TestLog::Message << "Error: expected Inf but returned " << returned << TestLog::EndMessage;
+               return false;
+       }
+
+       // NaN are always turned into NaN, too.
+       if (originalFloat.isNaN())
+       {
+               if (returnedFloat.isNaN())
+                       return true;
+
+               log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
+               return false;
+       }
+
+       // Check all rounding modes
+       for (int bitNdx = 0; bitNdx < 2; ++bitNdx)
+       {
+               if ((flags & (1u << bitNdx)) == 0)
+                       continue;       // This rounding mode is not selected.
+
+               const Float16   expectedFloat   (deFloat32To16Round(original, deRoundingMode(bitNdx)));
+
+               // Denormalized numbers can be flushed to zero.
+               if (expectedFloat.isDenorm() && returnedFloat.isZero())
+                       return true;
+
+               // If not matched in the above cases, they should have the same bit pattern.
+               if (expectedFloat.bits() == returnedFloat.bits())
+                       return true;
+       }
+
+       log << TestLog::Message << "Error: found unmatched 32-bit and 16-bit floats: " << originalFloat.bits() << " vs " << returned << TestLog::EndMessage;
+       return false;
+}
+
+bool compare32BitFloat (float expected, float returned, tcu::TestLog& log)
+{
+       const Float32   expectedFloat   (expected);
+       const Float32   returnedFloat   (returned);
+
+       // Denormalized numbers can be flushed to zero
+       if (expectedFloat.isDenorm() && returnedFloat.isZero())
+               return true;
+
+       if (expectedFloat.isNaN())
+       {
+               if (returnedFloat.isNaN())
+                       return true;
+
+               log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
+               return false;
+       }
+
+       if (returned == expected)
+               return true;
+
+       log << TestLog::Message << "Error: found unmatched 32-bit float: expected " << expectedFloat.bits() << " vs. returned " << returnedFloat.bits() << TestLog::EndMessage;
+       return false;
+}
+
+Move<VkBuffer> createBufferForResource(const DeviceInterface& vk, const VkDevice vkDevice, const Resource& resource, deUint32 queueFamilyIndex)
+{
+       const VkBufferCreateInfo        resourceBufferParams    =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                                           // sType
+               DE_NULL,                                                                                                                        // pNext
+               (VkBufferCreateFlags)0,                                                                                         // flags
+               (VkDeviceSize)resource.second->getNumBytes(),                                           // size
+               (VkBufferUsageFlags)getMatchingBufferUsageFlagBit(resource.first),      // usage
+               VK_SHARING_MODE_EXCLUSIVE,                                                                                      // sharingMode
+               1u,                                                                                                                                     // queueFamilyCount
+               &queueFamilyIndex,                                                                                                      // pQueueFamilyIndices
+       };
+
+       return createBuffer(vk, vkDevice, &resourceBufferParams);
+}
+
+TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance)
+{
+       const InstanceInterface&                                        vkInstance                              = context.getInstanceInterface();
+       const VkPhysicalDevice                                          vkPhysicalDevice                = context.getPhysicalDevice();
+       const deUint32                                                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
+       // Create a dedicated logic device with required extensions enabled for this test case.
+       const Unique<VkDevice>                                          vkDevice                                (createDeviceWithExtensions(vkInstance, vkPhysicalDevice, queueFamilyIndex, context.getDeviceExtensions(), instance.requiredDeviceExtensions));
+       const DeviceDriver                                                      vk                                              (vkInstance, *vkDevice);
+       const VkQueue                                                           queue                                   = getDeviceQueue(vk, *vkDevice, queueFamilyIndex, 0);
+       const tcu::UVec2                                                        renderSize                              (256, 256);
+       vector<ModuleHandleSp>                                          modules;
+       map<VkShaderStageFlagBits, VkShaderModule>      moduleByStage;
+       const int                                                                       testSpecificSeed                = 31354125;
+       const int                                                                       seed                                    = context.getTestContext().getCommandLine().getBaseSeed() ^ testSpecificSeed;
+       bool                                                                            supportsGeometry                = false;
+       bool                                                                            supportsTessellation    = false;
+       bool                                                                            hasTessellation         = false;
+       const bool                                                                      hasPushConstants                = !instance.pushConstants.empty();
+       const deUint32                                                          numResources                    = static_cast<deUint32>(instance.resources.inputs.size() + instance.resources.outputs.size());
+       const bool                                                                      needInterface                   = !instance.interfaces.empty();
+       const VkPhysicalDeviceFeatures&                         features                                = context.getDeviceFeatures();
+       const de::UniquePtr<Allocator>                          allocatorUptr                   (createAllocator(vkInstance, vkPhysicalDevice, vk, *vkDevice));
+       Allocator&                                                                      allocator                               = *allocatorUptr;
+
+       supportsGeometry                = features.geometryShader == VK_TRUE;
+       supportsTessellation    = features.tessellationShader == VK_TRUE;
+       hasTessellation                 = (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) ||
+                                                               (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
+
+       if (hasTessellation && !supportsTessellation)
+       {
+               throw tcu::NotSupportedError(std::string("Tessellation not supported"));
+       }
+
+       if ((instance.requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) &&
+               !supportsGeometry)
+       {
+               throw tcu::NotSupportedError(std::string("Geometry not supported"));
+       }
+
+       {
+               for (deUint32 featureNdx = 0; featureNdx < instance.requiredDeviceFeatures.size(); ++featureNdx)
+               {
+                       const string& feature = instance.requiredDeviceFeatures[featureNdx];
+
+                       if (feature == "shaderInt16")
+                       {
+                               if (features.shaderInt16 != VK_TRUE)
+                                       throw tcu::NotSupportedError(std::string("Device feature not supported: ") + feature);
+                       }
+                       else
+                       {
+                               throw tcu::InternalError(std::string("Unimplemented physical device feature: ") + feature);
+                       }
+               }
+       }
+
+       // 16bit storage features
+       {
+               if (!is16BitStorageFeaturesSupported(vkInstance, vkPhysicalDevice, context.getInstanceExtensions(), instance.requestedExtensionFeatures.ext16BitStorage))
+                       TCU_THROW(NotSupportedError, "Requested 16bit storage features not supported");
+       }
+
+       de::Random(seed).shuffle(instance.inputColors, instance.inputColors+4);
+       de::Random(seed).shuffle(instance.outputColors, instance.outputColors+4);
+       const Vec4                                                              vertexData[]                    =
+       {
+               // Upper left corner:
+               Vec4(-1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
+               Vec4(-0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
+               Vec4(-1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
+
+               // Upper right corner:
+               Vec4(+0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
+               Vec4(+1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
+               Vec4(+1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
+
+               // Lower left corner:
+               Vec4(-1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
+               Vec4(-0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
+               Vec4(-1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
+
+               // Lower right corner:
+               Vec4(+1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
+               Vec4(+1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
+               Vec4(+0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec()
+       };
+       const size_t                                                    singleVertexDataSize    = 2 * sizeof(Vec4);
+       const size_t                                                    vertexCount                             = sizeof(vertexData) / singleVertexDataSize;
+
+       Move<VkBuffer>                                                  vertexInputBuffer               ;
+       de::MovePtr<Allocation>                                 vertexInputMemory               ;
+       Move<VkBuffer>                                                  fragOutputBuffer                ;
+       de::MovePtr<Allocation>                                 fragOutputMemory                ;
+       Move<VkImage>                                                   fragOutputImage                 ;
+       de::MovePtr<Allocation>                                 fragOutputImageMemory   ;
+       Move<VkImageView>                                               fragOutputImageView             ;
+
+       const VkBufferCreateInfo                                vertexBufferParams              =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   //      VkStructureType         sType;
+               DE_NULL,                                                                //      const void*                     pNext;
+               0u,                                                                             //      VkBufferCreateFlags     flags;
+               (VkDeviceSize)sizeof(vertexData),               //      VkDeviceSize            size;
+               VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,              //      VkBufferUsageFlags      usage;
+               VK_SHARING_MODE_EXCLUSIVE,                              //      VkSharingMode           sharingMode;
+               1u,                                                                             //      deUint32                        queueFamilyCount;
+               &queueFamilyIndex,                                              //      const deUint32*         pQueueFamilyIndices;
+       };
+       const Unique<VkBuffer>                                  vertexBuffer                    (createBuffer(vk, *vkDevice, &vertexBufferParams));
+       const UniquePtr<Allocation>                             vertexBufferMemory              (allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *vertexBuffer), MemoryRequirement::HostVisible));
+
+       VK_CHECK(vk.bindBufferMemory(*vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
+
+       const VkDeviceSize                                              imageSizeBytes                  = (VkDeviceSize)(sizeof(deUint32)*renderSize.x()*renderSize.y());
+       const VkBufferCreateInfo                                readImageBufferParams   =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //      VkStructureType         sType;
+               DE_NULL,                                                                        //      const void*                     pNext;
+               0u,                                                                                     //      VkBufferCreateFlags     flags;
+               imageSizeBytes,                                                         //      VkDeviceSize            size;
+               VK_BUFFER_USAGE_TRANSFER_DST_BIT,                       //      VkBufferUsageFlags      usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                      //      VkSharingMode           sharingMode;
+               1u,                                                                                     //      deUint32                        queueFamilyCount;
+               &queueFamilyIndex,                                                      //      const deUint32*         pQueueFamilyIndices;
+       };
+       const Unique<VkBuffer>                                  readImageBuffer                 (createBuffer(vk, *vkDevice, &readImageBufferParams));
+       const UniquePtr<Allocation>                             readImageBufferMemory   (allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
+
+       VK_CHECK(vk.bindBufferMemory(*vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
+
+       VkImageCreateInfo                                               imageParams                             =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                    //      VkStructureType         sType;
+               DE_NULL,                                                                                                                                //      const void*                     pNext;
+               0u,                                                                                                                                             //      VkImageCreateFlags      flags;
+               VK_IMAGE_TYPE_2D,                                                                                                               //      VkImageType                     imageType;
+               VK_FORMAT_R8G8B8A8_UNORM,                                                                                               //      VkFormat                        format;
+               { renderSize.x(), renderSize.y(), 1 },                                                                  //      VkExtent3D                      extent;
+               1u,                                                                                                                                             //      deUint32                        mipLevels;
+               1u,                                                                                                                                             //      deUint32                        arraySize;
+               VK_SAMPLE_COUNT_1_BIT,                                                                                                  //      deUint32                        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                        queueFamilyCount;
+               &queueFamilyIndex,                                                                                                              //      const deUint32*         pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                              //      VkImageLayout           initialLayout;
+       };
+
+       const Unique<VkImage>                                   image                                   (createImage(vk, *vkDevice, &imageParams));
+       const UniquePtr<Allocation>                             imageMemory                             (allocator.allocate(getImageMemoryRequirements(vk, *vkDevice, *image), MemoryRequirement::Any));
+
+       VK_CHECK(vk.bindImageMemory(*vkDevice, *image, imageMemory->getMemory(), imageMemory->getOffset()));
+
+       if (needInterface)
+       {
+               // The pipeline renders four triangles, each with three vertexes.
+               // Test instantialization only provides four data points, each
+               // for one triangle. So we need allocate space of three times of
+               // input buffer's size.
+               const deUint32                                                  inputNumBytes                   = deUint32(instance.interfaces.getInputBuffer()->getNumBytes() * 3);
+               // Create an additional buffer and backing memory for one input variable.
+               const VkBufferCreateInfo                                vertexInputParams               =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //      VkStructureType         sType;
+                       DE_NULL,                                                                        //      const void*                     pNext;
+                       0u,                                                                                     //      VkBufferCreateFlags     flags;
+                       inputNumBytes,                                                          //      VkDeviceSize            size;
+                       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                      //      VkBufferUsageFlags      usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      //      VkSharingMode           sharingMode;
+                       1u,                                                                                     //      deUint32                        queueFamilyCount;
+                       &queueFamilyIndex,                                                      //      const deUint32*         pQueueFamilyIndices;
+               };
+
+               vertexInputBuffer = createBuffer(vk, *vkDevice, &vertexInputParams);
+               vertexInputMemory = allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *vertexInputBuffer), MemoryRequirement::HostVisible);
+               VK_CHECK(vk.bindBufferMemory(*vkDevice, *vertexInputBuffer, vertexInputMemory->getMemory(), vertexInputMemory->getOffset()));
+
+               // Create an additional buffer and backing memory for an output variable.
+               const VkDeviceSize                                              fragOutputImgSize               = (VkDeviceSize)(instance.interfaces.getOutputType().getNumBytes() * renderSize.x() * renderSize.y());
+               const VkBufferCreateInfo                                fragOutputParams                =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //      VkStructureType         sType;
+                       DE_NULL,                                                                        //      const void*                     pNext;
+                       0u,                                                                                     //      VkBufferCreateFlags     flags;
+                       fragOutputImgSize,                                                      //      VkDeviceSize            size;
+                       VK_BUFFER_USAGE_TRANSFER_DST_BIT,                       //      VkBufferUsageFlags      usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      //      VkSharingMode           sharingMode;
+                       1u,                                                                                     //      deUint32                        queueFamilyCount;
+                       &queueFamilyIndex,                                                      //      const deUint32*         pQueueFamilyIndices;
+               };
+               fragOutputBuffer = createBuffer(vk, *vkDevice, &fragOutputParams);
+               fragOutputMemory = allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *fragOutputBuffer), MemoryRequirement::HostVisible);
+               VK_CHECK(vk.bindBufferMemory(*vkDevice, *fragOutputBuffer, fragOutputMemory->getMemory(), fragOutputMemory->getOffset()));
+
+               // Create an additional image and backing memory for attachment.
+               // Reuse the previous imageParams since we only need to change the image format.
+               imageParams.format              = instance.interfaces.getOutputType().getVkFormat();
+               fragOutputImage                 = createImage(vk, *vkDevice, &imageParams);
+               fragOutputImageMemory   = allocator.allocate(getImageMemoryRequirements(vk, *vkDevice, *fragOutputImage), MemoryRequirement::Any);
+
+               VK_CHECK(vk.bindImageMemory(*vkDevice, *fragOutputImage, fragOutputImageMemory->getMemory(), fragOutputImageMemory->getOffset()));
+       }
+
+       vector<VkAttachmentDescription>                 colorAttDescs                   ;
+       vector<VkAttachmentReference>                   colorAttRefs                    ;
+       {
+               const VkAttachmentDescription           attDesc                                 =
+               {
+                       0u,                                                                                             //      VkAttachmentDescriptionFlags    flags;
+                       VK_FORMAT_R8G8B8A8_UNORM,                                               //      VkFormat                                                format;
+                       VK_SAMPLE_COUNT_1_BIT,                                                  //      deUint32                                                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;
+               };
+               colorAttDescs.push_back(attDesc);
+
+               const VkAttachmentReference                     attRef                                  =
+               {
+                       0u,                                                                                             //      deUint32                attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               //      VkImageLayout   layout;
+               };
+               colorAttRefs.push_back(attRef);
+       }
+
+       if (needInterface)
+       {
+               const VkAttachmentDescription           attDesc                                 =
+               {
+                       0u,                                                                                                     //      VkAttachmentDescriptionFlags    flags;
+                       instance.interfaces.getOutputType().getVkFormat(),      //      VkFormat                                                format;
+                       VK_SAMPLE_COUNT_1_BIT,                                                          //      deUint32                                                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;
+               };
+               colorAttDescs.push_back(attDesc);
+
+               const VkAttachmentReference                     attRef                                  =
+               {
+                       1u,                                                                                             //      deUint32                attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               //      VkImageLayout   layout;
+               };
+               colorAttRefs.push_back(attRef);
+       }
+
+       VkSubpassDescription                                    subpassDesc                             =
+       {
+               0u,                                                                                             //      VkSubpassDescriptionFlags               flags;
+               VK_PIPELINE_BIND_POINT_GRAPHICS,                                //      VkPipelineBindPoint                             pipelineBindPoint;
+               0u,                                                                                             //      deUint32                                                inputCount;
+               DE_NULL,                                                                                //      const VkAttachmentReference*    pInputAttachments;
+               1u,                                                                                             //      deUint32                                                colorCount;
+               colorAttRefs.data(),                                                    //      const VkAttachmentReference*    pColorAttachments;
+               DE_NULL,                                                                                //      const VkAttachmentReference*    pResolveAttachments;
+               DE_NULL,                                                                                //      const VkAttachmentReference*    pDepthStencilAttachment;
+               0u,                                                                                             //      deUint32                                                preserveCount;
+               DE_NULL,                                                                                //      const VkAttachmentReference*    pPreserveAttachments;
+
+       };
+       VkRenderPassCreateInfo                                  renderPassParams                =
+       {
+               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,              //      VkStructureType                                 sType;
+               DE_NULL,                                                                                //      const void*                                             pNext;
+               (VkRenderPassCreateFlags)0,
+               1u,                                                                                             //      deUint32                                                attachmentCount;
+               colorAttDescs.data(),                                                   //      const VkAttachmentDescription*  pAttachments;
+               1u,                                                                                             //      deUint32                                                subpassCount;
+               &subpassDesc,                                                                   //      const VkSubpassDescription*             pSubpasses;
+               0u,                                                                                             //      deUint32                                                dependencyCount;
+               DE_NULL,                                                                                //      const VkSubpassDependency*              pDependencies;
+       };
+
+       if (needInterface)
+       {
+               subpassDesc.colorAttachmentCount += 1;
+               renderPassParams.attachmentCount += 1;
+       }
+
+       const Unique<VkRenderPass>                              renderPass                              (createRenderPass(vk, *vkDevice, &renderPassParams));
+
+       const VkImageViewCreateInfo                             colorAttViewParams              =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,               //      VkStructureType                         sType;
+               DE_NULL,                                                                                //      const void*                                     pNext;
+               0u,                                                                                             //      VkImageViewCreateFlags          flags;
+               *image,                                                                                 //      VkImage                                         image;
+               VK_IMAGE_VIEW_TYPE_2D,                                                  //      VkImageViewType                         viewType;
+               VK_FORMAT_R8G8B8A8_UNORM,                                               //      VkFormat                                        format;
+               {
+                       VK_COMPONENT_SWIZZLE_R,
+                       VK_COMPONENT_SWIZZLE_G,
+                       VK_COMPONENT_SWIZZLE_B,
+                       VK_COMPONENT_SWIZZLE_A
+               },                                                                                              //      VkChannelMapping                        channels;
+               {
+                       VK_IMAGE_ASPECT_COLOR_BIT,                                              //      VkImageAspectFlags      aspectMask;
+                       0u,                                                                                             //      deUint32                        baseMipLevel;
+                       1u,                                                                                             //      deUint32                        mipLevels;
+                       0u,                                                                                             //      deUint32                        baseArrayLayer;
+                       1u,                                                                                             //      deUint32                        arraySize;
+               },                                                                                              //      VkImageSubresourceRange         subresourceRange;
+       };
+       const Unique<VkImageView>                               colorAttView                    (createImageView(vk, *vkDevice, &colorAttViewParams));
+
+       vector<VkImageView>                                             attViews                                ;
+       attViews.push_back(*colorAttView);
+
+       // Handle resources requested by the test instantiation.
+       const deUint32                                                  numInResources                  = static_cast<deUint32>(instance.resources.inputs.size());
+       const deUint32                                                  numOutResources                 = static_cast<deUint32>(instance.resources.outputs.size());
+       // These variables should be placed out of the following if block to avoid deallocation after out of scope.
+       vector<AllocationSp>                                    inResourceMemories              ;
+       vector<AllocationSp>                                    outResourceMemories             ;
+       vector<BufferHandleSp>                                  inResourceBuffers               ;
+       vector<BufferHandleSp>                                  outResourceBuffers              ;
+       Move<VkDescriptorPool>                                  descriptorPool                  ;
+       Move<VkDescriptorSetLayout>                             setLayout                               ;
+       VkDescriptorSetLayout                                   rawSetLayout                    = DE_NULL;
+       VkDescriptorSet                                                 rawSet                                  = DE_NULL;
+
+       if (numResources != 0)
+       {
+               vector<VkDescriptorSetLayoutBinding>    setLayoutBindings       ;
+               vector<VkDescriptorPoolSize>                    poolSizes                       ;
+
+               setLayoutBindings.reserve(numResources);
+               poolSizes.reserve(numResources);
+
+               // Process all input resources.
+               for (deUint32 inputNdx = 0; inputNdx < numInResources; ++inputNdx)
+               {
+                       const Resource&                                 resource                                = instance.resources.inputs[inputNdx];
+                       // Create buffer and allocate memory.
+                       Move<VkBuffer>                                  resourceBuffer                  = createBufferForResource(vk, *vkDevice, resource, queueFamilyIndex);
+                       de::MovePtr<Allocation>                 resourceMemory                  = allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *resourceBuffer), MemoryRequirement::HostVisible);
+
+                       VK_CHECK(vk.bindBufferMemory(*vkDevice, *resourceBuffer, resourceMemory->getMemory(), resourceMemory->getOffset()));
+
+                       // Copy data to memory.
+                       const VkMappedMemoryRange               range                                   =
+                       {
+                               VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,                          //      VkStructureType sType;
+                               DE_NULL,                                                                                        //      const void*             pNext;
+                               resourceMemory->getMemory(),                                            //      VkDeviceMemory  mem;
+                               0,                                                                                                      //      VkDeviceSize    offset;
+                               VK_WHOLE_SIZE,                                                                          //      VkDeviceSize    size;
+                       };
+
+                       deMemcpy(resourceMemory->getHostPtr(), resource.second->data(), resource.second->getNumBytes());
+                       VK_CHECK(vk.flushMappedMemoryRanges(*vkDevice, 1u, &range));
+
+                       inResourceMemories.push_back(AllocationSp(resourceMemory.release()));
+                       inResourceBuffers.push_back(BufferHandleSp(new BufferHandleUp(resourceBuffer)));
+
+                       // Prepare descriptor bindings and pool sizes for creating descriptor set layout and pool.
+                       const VkDescriptorSetLayoutBinding      binding                         =
+                       {
+                               inputNdx,                                                                                       // binding
+                               resource.first,                                                                         // descriptorType
+                               1u,                                                                                                     // descriptorCount
+                               VK_SHADER_STAGE_ALL_GRAPHICS,                                           // stageFlags
+                               DE_NULL,                                                                                        // pImmutableSamplers
+                       };
+                       setLayoutBindings.push_back(binding);
+
+                       // Note: the following code doesn't check and unify descriptors of the same type.
+                       const VkDescriptorPoolSize              poolSize                                =
+                       {
+                               resource.first,                                                                         // type
+                               1u,                                                                                                     // descriptorCount
+                       };
+                       poolSizes.push_back(poolSize);
+               }
+
+               // Process all output resources.
+               for (deUint32 outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
+               {
+                       const Resource&                                 resource                                = instance.resources.outputs[outputNdx];
+                       // Create buffer and allocate memory.
+                       Move<VkBuffer>                                  resourceBuffer                  = createBufferForResource(vk, *vkDevice, resource, queueFamilyIndex);
+                       de::MovePtr<Allocation>                 resourceMemory                  = allocator.allocate(getBufferMemoryRequirements(vk, *vkDevice, *resourceBuffer), MemoryRequirement::HostVisible);
+
+                       VK_CHECK(vk.bindBufferMemory(*vkDevice, *resourceBuffer, resourceMemory->getMemory(), resourceMemory->getOffset()));
+
+                       // Fill memory with all ones.
+                       const VkMappedMemoryRange               range                                   =
+                       {
+                               VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,                          //      VkStructureType sType;
+                               DE_NULL,                                                                                        //      const void*             pNext;
+                               resourceMemory->getMemory(),                                            //      VkDeviceMemory  mem;
+                               0,                                                                                                      //      VkDeviceSize    offset;
+                               VK_WHOLE_SIZE,                                                                          //      VkDeviceSize    size;
+                       };
+
+                       deMemset((deUint8*)resourceMemory->getHostPtr(), 0xff, resource.second->getNumBytes());
+                       VK_CHECK(vk.flushMappedMemoryRanges(*vkDevice, 1u, &range));
+
+                       outResourceMemories.push_back(AllocationSp(resourceMemory.release()));
+                       outResourceBuffers.push_back(BufferHandleSp(new BufferHandleUp(resourceBuffer)));
+
+                       // Prepare descriptor bindings and pool sizes for creating descriptor set layout and pool.
+                       const VkDescriptorSetLayoutBinding      binding                         =
+                       {
+                               numInResources  + outputNdx,                                            // binding
+                               resource.first,                                                                         // descriptorType
+                               1u,                                                                                                     // descriptorCount
+                               VK_SHADER_STAGE_ALL_GRAPHICS,                                           // stageFlags
+                               DE_NULL,                                                                                        // pImmutableSamplers
+                       };
+                       setLayoutBindings.push_back(binding);
+
+                       // Note: the following code doesn't check and unify descriptors of the same type.
+                       const VkDescriptorPoolSize              poolSize                                =
+                       {
+                               resource.first,                                                                         // type
+                               1u,                                                                                                     // descriptorCount
+                       };
+                       poolSizes.push_back(poolSize);
+               }
+
+               // Create descriptor set layout, descriptor pool, and allocate descriptor set.
+               const VkDescriptorSetLayoutCreateInfo   setLayoutParams         =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,    // sType
+                       DE_NULL,                                                                                                // pNext
+                       (VkDescriptorSetLayoutCreateFlags)0,                                    // flags
+                       numResources,                                                                                   // bindingCount
+                       setLayoutBindings.data(),                                                               // pBindings
+               };
+               setLayout                                                                                                       = createDescriptorSetLayout(vk, *vkDevice, &setLayoutParams);
+               rawSetLayout                                                                                            = *setLayout;
+
+               const VkDescriptorPoolCreateInfo                poolParams                      =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,                  // sType
+                       DE_NULL,                                                                                                // pNext
+                       (VkDescriptorPoolCreateFlags)0,                                                 // flags
+                       1u,                                                                                                             // maxSets
+                       numResources,                                                                                   // poolSizeCount
+                       poolSizes.data(),                                                                               // pPoolSizes
+               };
+               descriptorPool                                                                                          = createDescriptorPool(vk, *vkDevice, &poolParams);
+
+               const VkDescriptorSetAllocateInfo               setAllocParams          =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,                 // sType
+                       DE_NULL,                                                                                                // pNext
+                       *descriptorPool,                                                                                // descriptorPool
+                       1u,                                                                                                             // descriptorSetCount
+                       &rawSetLayout,                                                                                  // pSetLayouts
+               };
+               VK_CHECK(vk.allocateDescriptorSets(*vkDevice, &setAllocParams, &rawSet));
+
+               // Update descriptor set.
+               vector<VkWriteDescriptorSet>                    writeSpecs                      ;
+               vector<VkDescriptorBufferInfo>                  dBufferInfos            ;
+
+               writeSpecs.reserve(numResources);
+               dBufferInfos.reserve(numResources);
+
+               for (deUint32 inputNdx = 0; inputNdx < numInResources; ++inputNdx)
+               {
+                       const VkDescriptorBufferInfo            bufInfo                         =
+                       {
+                               **inResourceBuffers[inputNdx],                                          // buffer
+                               0,                                                                                                      // offset
+                               VK_WHOLE_SIZE,                                                                          // size
+                       };
+                       dBufferInfos.push_back(bufInfo);
+
+                       const VkWriteDescriptorSet                      writeSpec                       = {
+                               VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                         // sType
+                               DE_NULL,                                                                                        // pNext
+                               rawSet,                                                                                         // dstSet
+                               inputNdx,                                                                                       // binding
+                               0,                                                                                                      // dstArrayElement
+                               1u,                                                                                                     // descriptorCount
+                               instance.resources.inputs[inputNdx].first,                      // descriptorType
+                               DE_NULL,                                                                                        // pImageInfo
+                               &dBufferInfos.back(),                                                           // pBufferInfo
+                               DE_NULL,                                                                                        // pTexelBufferView
+                       };
+                       writeSpecs.push_back(writeSpec);
+               }
+               for (deUint32 outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
+               {
+                       const VkDescriptorBufferInfo            bufInfo                         =
+                       {
+                               **outResourceBuffers[outputNdx],                                        // buffer
+                               0,                                                                                                      // offset
+                               VK_WHOLE_SIZE,                                                                          // size
+                       };
+                       dBufferInfos.push_back(bufInfo);
+
+                       const VkWriteDescriptorSet                      writeSpec                       = {
+                               VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                         // sType
+                               DE_NULL,                                                                                        // pNext
+                               rawSet,                                                                                         // dstSet
+                               numInResources + outputNdx,                                                     // binding
+                               0,                                                                                                      // dstArrayElement
+                               1u,                                                                                                     // descriptorCount
+                               instance.resources.outputs[outputNdx].first,            // descriptorType
+                               DE_NULL,                                                                                        // pImageInfo
+                               &dBufferInfos.back(),                                                           // pBufferInfo
+                               DE_NULL,                                                                                        // pTexelBufferView
+                       };
+                       writeSpecs.push_back(writeSpec);
+               }
+               vk.updateDescriptorSets(*vkDevice, numResources, writeSpecs.data(), 0, DE_NULL);
+       }
+
+       // Pipeline layout
+       VkPipelineLayoutCreateInfo                              pipelineLayoutParams    =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,                  //      VkStructureType                                 sType;
+               DE_NULL,                                                                                                //      const void*                                             pNext;
+               (VkPipelineLayoutCreateFlags)0,
+               0u,                                                                                                             //      deUint32                                                descriptorSetCount;
+               DE_NULL,                                                                                                //      const VkDescriptorSetLayout*    pSetLayouts;
+               0u,                                                                                                             //      deUint32                                                pushConstantRangeCount;
+               DE_NULL,                                                                                                //      const VkPushConstantRange*              pPushConstantRanges;
+       };
+
+       VkPushConstantRange                                             pushConstantRange               =
+       {
+               VK_SHADER_STAGE_ALL_GRAPHICS,                                                   // VkShaderStageFlags    stageFlags;
+               0,                                                                                                              // uint32_t              offset;
+               0,                                                                                                              // uint32_t              size;
+       };
+       if (hasPushConstants)
+       {
+               pushConstantRange.size                                          = static_cast<deUint32>(instance.pushConstants.getBuffer()->getNumBytes());
+               pipelineLayoutParams.pushConstantRangeCount     = 1;
+               pipelineLayoutParams.pPushConstantRanges        = &pushConstantRange;
+       }
+       if (numResources != 0)
+       {
+               // Update pipeline layout with the descriptor set layout.
+               pipelineLayoutParams.setLayoutCount                                                             = 1;
+               pipelineLayoutParams.pSetLayouts                                                                = &rawSetLayout;
+       }
+       const Unique<VkPipelineLayout>                  pipelineLayout                  (createPipelineLayout(vk, *vkDevice, &pipelineLayoutParams));
+
+       // Pipeline
+       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.resize(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;
+               DE_NULL,                                                                                                        //      const void*                     pNext;
+               (VkPipelineDepthStencilStateCreateFlags)0,
+               DE_FALSE,                                                                                                       //      deUint32                        depthTestEnable;
+               DE_FALSE,                                                                                                       //      deUint32                        depthWriteEnable;
+               VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp                     depthCompareOp;
+               DE_FALSE,                                                                                                       //      deUint32                        depthBoundsTestEnable;
+               DE_FALSE,                                                                                                       //      deUint32                        stencilTestEnable;
+               {
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilFailOp;
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilPassOp;
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilDepthFailOp;
+                       VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp     stencilCompareOp;
+                       0u,                                                                                                                     //      deUint32        stencilCompareMask;
+                       0u,                                                                                                                     //      deUint32        stencilWriteMask;
+                       0u,                                                                                                                     //      deUint32        stencilReference;
+               },                                                                                                                      //      VkStencilOpState        front;
+               {
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilFailOp;
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilPassOp;
+                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilDepthFailOp;
+                       VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp     stencilCompareOp;
+                       0u,                                                                                                                     //      deUint32        stencilCompareMask;
+                       0u,                                                                                                                     //      deUint32        stencilWriteMask;
+                       0u,                                                                                                                     //      deUint32        stencilReference;
+               },                                                                                                                      //      VkStencilOpState        back;
+               -1.0f,                                                                                                          //      float                           minDepthBounds;
+               +1.0f,                                                                                                          //      float                           maxDepthBounds;
+       };
+       const VkViewport                                                viewport0                               =
+       {
+               0.0f,                                                                                                           //      float   originX;
+               0.0f,                                                                                                           //      float   originY;
+               (float)renderSize.x(),                                                                          //      float   width;
+               (float)renderSize.y(),                                                                          //      float   height;
+               0.0f,                                                                                                           //      float   minDepth;
+               1.0f,                                                                                                           //      float   maxDepth;
+       };
+       const VkRect2D                                                  scissor0                                =
+       {
+               {
+                       0u,                                                                                                                     //      deInt32 x;
+                       0u,                                                                                                                     //      deInt32 y;
+               },                                                                                                                      //      VkOffset2D      offset;
+               {
+                       renderSize.x(),                                                                                         //      deInt32 width;
+                       renderSize.y(),                                                                                         //      deInt32 height;
+               },                                                                                                                      //      VkExtent2D      extent;
+       };
+       const VkPipelineViewportStateCreateInfo         viewportParams                  =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,          //      VkStructureType         sType;
+               DE_NULL,                                                                                                        //      const void*                     pNext;
+               (VkPipelineViewportStateCreateFlags)0,
+               1u,                                                                                                                     //      deUint32                        viewportCount;
+               &viewport0,
+               1u,
+               &scissor0
+       };
+       const VkSampleMask                                                      sampleMask                              = ~0u;
+       const VkPipelineMultisampleStateCreateInfo      multisampleParams               =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       //      VkStructureType                 sType;
+               DE_NULL,                                                                                                        //      const void*                             pNext;
+               (VkPipelineMultisampleStateCreateFlags)0,
+               VK_SAMPLE_COUNT_1_BIT,                                                                          //      VkSampleCountFlagBits   rasterSamples;
+               DE_FALSE,                                                                                                       //      deUint32                                sampleShadingEnable;
+               0.0f,                                                                                                           //      float                                   minSampleShading;
+               &sampleMask,                                                                                            //      const VkSampleMask*             pSampleMask;
+               DE_FALSE,                                                                                                       //      VkBool32                                alphaToCoverageEnable;
+               DE_FALSE,                                                                                                       //      VkBool32                                alphaToOneEnable;
+       };
+       const VkPipelineRasterizationStateCreateInfo    rasterParams            =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,     //      VkStructureType sType;
+               DE_NULL,                                                                                                        //      const void*             pNext;
+               (VkPipelineRasterizationStateCreateFlags)0,
+               DE_TRUE,                                                                                                        //      deUint32                depthClipEnable;
+               DE_FALSE,                                                                                                       //      deUint32                rasterizerDiscardEnable;
+               VK_POLYGON_MODE_FILL,                                                                           //      VkFillMode              fillMode;
+               VK_CULL_MODE_NONE,                                                                                      //      VkCullMode              cullMode;
+               VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                        //      VkFrontFace             frontFace;
+               VK_FALSE,                                                                                                       //      VkBool32                depthBiasEnable;
+               0.0f,                                                                                                           //      float                   depthBias;
+               0.0f,                                                                                                           //      float                   depthBiasClamp;
+               0.0f,                                                                                                           //      float                   slopeScaledDepthBias;
+               1.0f,                                                                                                           //      float                   lineWidth;
+       };
+       const VkPrimitiveTopology topology = 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,
+               topology,                                                                                                               //      VkPrimitiveTopology     topology;
+               DE_FALSE,                                                                                                               //      deUint32                        primitiveRestartEnable;
+       };
+
+       vector<VkVertexInputBindingDescription>         vertexBindings;
+       vector<VkVertexInputAttributeDescription>       vertexAttribs;
+
+       const VkVertexInputBindingDescription           vertexBinding0                  =
+       {
+               0u,                                                                     // deUint32                                     binding;
+               deUint32(singleVertexDataSize),         // deUint32                                     strideInBytes;
+               VK_VERTEX_INPUT_RATE_VERTEX                     // VkVertexInputStepRate        stepRate;
+       };
+       vertexBindings.push_back(vertexBinding0);
+
+       {
+               VkVertexInputAttributeDescription               attr0                                   =
+               {
+                       0u,                                                                     // deUint32     location;
+                       0u,                                                                     // deUint32     binding;
+                       VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                       0u                                                                      // deUint32     offsetInBytes;
+               };
+               vertexAttribs.push_back(attr0);
+
+               VkVertexInputAttributeDescription               attr1                                   =
+               {
+                       1u,                                                                     // deUint32     location;
+                       0u,                                                                     // deUint32     binding;
+                       VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
+                       sizeof(Vec4),                                           // deUint32     offsetInBytes;
+               };
+               vertexAttribs.push_back(attr1);
+       };
+
+       // If the test instantiation has additional input/output interface variables, we need to create additional bindings.
+       // Right now we only support one additional input varible for the vertex stage, and that will be bound to binding #1
+       // with location #2.
+       if (needInterface)
+       {
+               const VkVertexInputBindingDescription   vertexBinding1                  =
+               {
+                       1u,                                                                                                     // deUint32                                     binding;
+                       instance.interfaces.getInputType().getNumBytes(),       // deUint32                                     strideInBytes;
+                       VK_VERTEX_INPUT_RATE_VERTEX                                                     // VkVertexInputStepRate        stepRate;
+               };
+               vertexBindings.push_back(vertexBinding1);
+
+               VkVertexInputAttributeDescription               attr                                    =
+               {
+                       2u,                                                                                                     // deUint32     location;
+                       1u,                                                                                                     // deUint32     binding;
+                       instance.interfaces.getInputType().getVkFormat(),       // VkFormat     format;
+                       0,                                                                                                      // deUint32     offsetInBytes;
+               };
+               vertexAttribs.push_back(attr);
+       }
+
+       VkPipelineVertexInputStateCreateInfo            vertexInputStateParams  =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,      //      VkStructureType                                                         sType;
+               DE_NULL,                                                                                                        //      const void*                                                                     pNext;
+               (VkPipelineVertexInputStateCreateFlags)0,
+               1u,                                                                                                                     //      deUint32                                                                        bindingCount;
+               vertexBindings.data(),                                                                          //      const VkVertexInputBindingDescription*          pVertexBindingDescriptions;
+               2u,                                                                                                                     //      deUint32                                                                        attributeCount;
+               vertexAttribs.data(),                                                                           //      const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions;
+       };
+
+       if (needInterface)
+       {
+               vertexInputStateParams.vertexBindingDescriptionCount += 1;
+               vertexInputStateParams.vertexAttributeDescriptionCount += 1;
+       }
+
+       vector<VkPipelineColorBlendAttachmentState>     attBlendStates                  ;
+       const VkPipelineColorBlendAttachmentState       attBlendState                   =
+       {
+               DE_FALSE,                                                                                                       //      deUint32                blendEnable;
+               VK_BLEND_FACTOR_ONE,                                                                            //      VkBlend                 srcBlendColor;
+               VK_BLEND_FACTOR_ZERO,                                                                           //      VkBlend                 destBlendColor;
+               VK_BLEND_OP_ADD,                                                                                        //      VkBlendOp               blendOpColor;
+               VK_BLEND_FACTOR_ONE,                                                                            //      VkBlend                 srcBlendAlpha;
+               VK_BLEND_FACTOR_ZERO,                                                                           //      VkBlend                 destBlendAlpha;
+               VK_BLEND_OP_ADD,                                                                                        //      VkBlendOp               blendOpAlpha;
+               (VK_COLOR_COMPONENT_R_BIT|
+                VK_COLOR_COMPONENT_G_BIT|
+                VK_COLOR_COMPONENT_B_BIT|
+                VK_COLOR_COMPONENT_A_BIT),                                                                     //      VkChannelFlags  channelWriteMask;
+       };
+       attBlendStates.push_back(attBlendState);
+
+       if (needInterface)
+               attBlendStates.push_back(attBlendState);
+
+       VkPipelineColorBlendStateCreateInfo             blendParams                             =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       //      VkStructureType                                                         sType;
+               DE_NULL,                                                                                                        //      const void*                                                                     pNext;
+               (VkPipelineColorBlendStateCreateFlags)0,
+               DE_FALSE,                                                                                                       //      VkBool32                                                                        logicOpEnable;
+               VK_LOGIC_OP_COPY,                                                                                       //      VkLogicOp                                                                       logicOp;
+               1u,                                                                                                                     //      deUint32                                                                        attachmentCount;
+               attBlendStates.data(),                                                                          //      const VkPipelineColorBlendAttachmentState*      pAttachments;
+               { 0.0f, 0.0f, 0.0f, 0.0f },                                                                     //      float                                                                           blendConst[4];
+       };
+       if (needInterface)
+       {
+               blendParams.attachmentCount += 1;
+       }
+       const VkPipelineTessellationStateCreateInfo     tessellationState       =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineTessellationStateCreateFlags)0,
+               3u
+       };
+
+       const VkPipelineTessellationStateCreateInfo* tessellationInfo   =       hasTessellation ? &tessellationState: DE_NULL;
+       const VkGraphicsPipelineCreateInfo              pipelineParams                  =
+       {
+               VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,                //      VkStructureType                                                                 sType;
+               DE_NULL,                                                                                                //      const void*                                                                             pNext;
+               0u,                                                                                                             //      VkPipelineCreateFlags                                                   flags;
+               (deUint32)shaderStageParams.size(),                                             //      deUint32                                                                                stageCount;
+               &shaderStageParams[0],                                                                  //      const VkPipelineShaderStageCreateInfo*                  pStages;
+               &vertexInputStateParams,                                                                //      const VkPipelineVertexInputStateCreateInfo*             pVertexInputState;
+               &inputAssemblyParams,                                                                   //      const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState;
+               tessellationInfo,                                                                               //      const VkPipelineTessellationStateCreateInfo*    pTessellationState;
+               &viewportParams,                                                                                //      const VkPipelineViewportStateCreateInfo*                pViewportState;
+               &rasterParams,                                                                                  //      const VkPipelineRasterStateCreateInfo*                  pRasterState;
+               &multisampleParams,                                                                             //      const VkPipelineMultisampleStateCreateInfo*             pMultisampleState;
+               &depthStencilParams,                                                                    //      const VkPipelineDepthStencilStateCreateInfo*    pDepthStencilState;
+               &blendParams,                                                                                   //      const VkPipelineColorBlendStateCreateInfo*              pColorBlendState;
+               (const VkPipelineDynamicStateCreateInfo*)DE_NULL,               //      const VkPipelineDynamicStateCreateInfo*                 pDynamicState;
+               *pipelineLayout,                                                                                //      VkPipelineLayout                                                                layout;
+               *renderPass,                                                                                    //      VkRenderPass                                                                    renderPass;
+               0u,                                                                                                             //      deUint32                                                                                subpass;
+               DE_NULL,                                                                                                //      VkPipeline                                                                              basePipelineHandle;
+               0u,                                                                                                             //      deInt32                                                                                 basePipelineIndex;
+       };
+
+       const Unique<VkPipeline>                                pipeline                                (createGraphicsPipeline(vk, *vkDevice, DE_NULL, &pipelineParams));
+
+       if (needInterface)
+       {
+               const VkImageViewCreateInfo                     fragOutputViewParams    =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,                       //      VkStructureType                         sType;
+                       DE_NULL,                                                                                        //      const void*                                     pNext;
+                       0u,                                                                                                     //      VkImageViewCreateFlags          flags;
+                       *fragOutputImage,                                                                       //      VkImage                                         image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                          //      VkImageViewType                         viewType;
+                       instance.interfaces.getOutputType().getVkFormat(),      //      VkFormat                                        format;
+                       {
+                               VK_COMPONENT_SWIZZLE_R,
+                               VK_COMPONENT_SWIZZLE_G,
+                               VK_COMPONENT_SWIZZLE_B,
+                               VK_COMPONENT_SWIZZLE_A
+                       },                                                                                                      //      VkChannelMapping                        channels;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                                              //      VkImageAspectFlags      aspectMask;
+                               0u,                                                                                             //      deUint32                        baseMipLevel;
+                               1u,                                                                                             //      deUint32                        mipLevels;
+                               0u,                                                                                             //      deUint32                        baseArrayLayer;
+                               1u,                                                                                             //      deUint32                        arraySize;
+                       },                                                                                                      //      VkImageSubresourceRange         subresourceRange;
+               };
+               fragOutputImageView = createImageView(vk, *vkDevice, &fragOutputViewParams);
+               attViews.push_back(*fragOutputImageView);
+       }
+
+       // Framebuffer
+       VkFramebufferCreateInfo                                 framebufferParams               =
+       {
+               VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                              //      VkStructureType         sType;
+               DE_NULL,                                                                                                //      const void*                     pNext;
+               (VkFramebufferCreateFlags)0,
+               *renderPass,                                                                                    //      VkRenderPass            renderPass;
+               1u,                                                                                                             //      deUint32                        attachmentCount;
+               attViews.data(),                                                                                //      const VkImageView*      pAttachments;
+               (deUint32)renderSize.x(),                                                               //      deUint32                        width;
+               (deUint32)renderSize.y(),                                                               //      deUint32                        height;
+               1u,                                                                                                             //      deUint32                        layers;
+       };
+
+       if (needInterface)
+               framebufferParams.attachmentCount += 1;
+
+       const Unique<VkFramebuffer>                             framebuffer                             (createFramebuffer(vk, *vkDevice, &framebufferParams));
+
+       const Unique<VkCommandPool>                             cmdPool                                 (createCommandPool(vk, *vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+
+       // Command buffer
+       const Unique<VkCommandBuffer>                   cmdBuf                                  (allocateCommandBuffer(vk, *vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+
+       const VkCommandBufferBeginInfo                  cmdBufBeginParams               =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,                    //      VkStructureType                         sType;
+               DE_NULL,                                                                                                //      const void*                                     pNext;
+               (VkCommandBufferUsageFlags)0,
+               (const VkCommandBufferInheritanceInfo*)DE_NULL,
+       };
+
+       // Record commands
+       VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
+
+       {
+               const VkMemoryBarrier                   vertFlushBarrier        =
+               {
+                       VK_STRUCTURE_TYPE_MEMORY_BARRIER,                       //      VkStructureType         sType;
+                       DE_NULL,                                                                        //      const void*                     pNext;
+                       VK_ACCESS_HOST_WRITE_BIT,                                       //      VkMemoryOutputFlags     outputMask;
+                       VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,            //      VkMemoryInputFlags      inputMask;
+               };
+               vector<VkImageMemoryBarrier>    colorAttBarriers        ;
+
+               VkImageMemoryBarrier                    imgBarrier          =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         //      VkStructureType                 sType;
+                       DE_NULL,                                                                        //      const void*                             pNext;
+                       0u,                                                                                     //      VkMemoryOutputFlags             outputMask;
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           //      VkMemoryInputFlags              inputMask;
+                       VK_IMAGE_LAYOUT_UNDEFINED,                                      //      VkImageLayout                   oldLayout;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       //      VkImageLayout                   newLayout;
+                       queueFamilyIndex,                                                       //      deUint32                                srcQueueFamilyIndex;
+                       queueFamilyIndex,                                                       //      deUint32                                destQueueFamilyIndex;
+                       *image,                                                                         //      VkImage                                 image;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                                      //      VkImageAspect   aspect;
+                               0u,                                                                                     //      deUint32                baseMipLevel;
+                               1u,                                                                                     //      deUint32                mipLevels;
+                               0u,                                                                                     //      deUint32                baseArraySlice;
+                               1u,                                                                                     //      deUint32                arraySize;
+                       }                                                                                       //      VkImageSubresourceRange subresourceRange;
+               };
+               colorAttBarriers.push_back(imgBarrier);
+               if (needInterface)
+               {
+                       imgBarrier.image = *fragOutputImage;
+                       colorAttBarriers.push_back(imgBarrier);
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 1, &vertFlushBarrier, 0, (const VkBufferMemoryBarrier*)DE_NULL, 2, colorAttBarriers.data());
+               }
+               else
+               {
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 1, &vertFlushBarrier, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, colorAttBarriers.data());
+               }
+       }
+
+       {
+               vector<VkClearValue>                    clearValue              ;
+               clearValue.push_back(makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f));
+               if (needInterface)
+               {
+                       clearValue.push_back(makeClearValueColorU32(0, 0, 0, 0));
+               }
+               VkRenderPassBeginInfo                   passBeginParams =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                       //      VkStructureType         sType;
+                       DE_NULL,                                                                                        //      const void*                     pNext;
+                       *renderPass,                                                                            //      VkRenderPass            renderPass;
+                       *framebuffer,                                                                           //      VkFramebuffer           framebuffer;
+                       { { 0, 0 }, { renderSize.x(), renderSize.y() } },       //      VkRect2D                        renderArea;
+                       1u,                                                                                                     //      deUint32                        clearValueCount;
+                       clearValue.data(),                                                                      //      const VkClearValue*     pClearValues;
+               };
+               if (needInterface)
+               {
+                       passBeginParams.clearValueCount += 1;
+               }
+               vk.cmdBeginRenderPass(*cmdBuf, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
+       }
+
+       vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+       {
+               const VkDeviceSize bindingOffset = 0;
+               vk.cmdBindVertexBuffers(*cmdBuf, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
+       }
+       if (needInterface)
+       {
+               const VkDeviceSize bindingOffset = 0;
+               vk.cmdBindVertexBuffers(*cmdBuf, 1u, 1u, &vertexInputBuffer.get(), &bindingOffset);
+       }
+       if (hasPushConstants)
+       {
+               const deUint32  size    = static_cast<deUint32>(instance.pushConstants.getBuffer()->getNumBytes());
+               const void*             data    = instance.pushConstants.getBuffer()->data();
+
+               vk.cmdPushConstants(*cmdBuf, *pipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, size, data);
+       }
+       if (numResources != 0)
+       {
+               // Bind to set number 0.
+               vk.cmdBindDescriptorSets(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0, 1, &rawSet, 0, DE_NULL);
+       }
+       vk.cmdDraw(*cmdBuf, deUint32(vertexCount), 1u /*run pipeline once*/, 0u /*first vertex*/, 0u /*first instanceIndex*/);
+       vk.cmdEndRenderPass(*cmdBuf);
+
+       {
+               vector<VkImageMemoryBarrier>    renderFinishBarrier;
+               VkImageMemoryBarrier                    imgBarrier                              =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         //      VkStructureType                 sType;
+                       DE_NULL,                                                                        //      const void*                             pNext;
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           //      VkMemoryOutputFlags             outputMask;
+                       VK_ACCESS_TRANSFER_READ_BIT,                            //      VkMemoryInputFlags              inputMask;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       //      VkImageLayout                   oldLayout;
+                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,           //      VkImageLayout                   newLayout;
+                       queueFamilyIndex,                                                       //      deUint32                                srcQueueFamilyIndex;
+                       queueFamilyIndex,                                                       //      deUint32                                destQueueFamilyIndex;
+                       *image,                                                                         //      VkImage                                 image;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                                      //      VkImageAspectFlags      aspectMask;
+                               0u,                                                                                     //      deUint32                        baseMipLevel;
+                               1u,                                                                                     //      deUint32                        mipLevels;
+                               0u,                                                                                     //      deUint32                        baseArraySlice;
+                               1u,                                                                                     //      deUint32                        arraySize;
+                       }                                                                                       //      VkImageSubresourceRange subresourceRange;
+               };
+               renderFinishBarrier.push_back(imgBarrier);
+
+               if (needInterface)
+               {
+                       imgBarrier.image = *fragOutputImage;
+                       renderFinishBarrier.push_back(imgBarrier);
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 2, renderFinishBarrier.data());
+               }
+               else
+               {
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, renderFinishBarrier.data());
+               }
+       }
+
+       {
+               const VkBufferImageCopy copyParams      =
+               {
+                       (VkDeviceSize)0u,                                               //      VkDeviceSize                    bufferOffset;
+                       (deUint32)renderSize.x(),                               //      deUint32                                bufferRowLength;
+                       (deUint32)renderSize.y(),                               //      deUint32                                bufferImageHeight;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                              //      VkImageAspect           aspect;
+                               0u,                                                                             //      deUint32                        mipLevel;
+                               0u,                                                                             //      deUint32                        arrayLayer;
+                               1u,                                                                             //      deUint32                        arraySize;
+                       },                                                                              //      VkImageSubresourceCopy  imageSubresource;
+                       { 0u, 0u, 0u },                                                 //      VkOffset3D                              imageOffset;
+                       { renderSize.x(), renderSize.y(), 1u }  //      VkExtent3D                              imageExtent;
+               };
+               vk.cmdCopyImageToBuffer(*cmdBuf, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
+
+               if (needInterface)
+               {
+                       vk.cmdCopyImageToBuffer(*cmdBuf, *fragOutputImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *fragOutputBuffer, 1u, &copyParams);
+               }
+       }
+
+       {
+               vector<VkBufferMemoryBarrier> cpFinishBarriers          ;
+               VkBufferMemoryBarrier                   copyFinishBarrier       =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,        //      VkStructureType         sType;
+                       DE_NULL,                                                                        //      const void*                     pNext;
+                       VK_ACCESS_TRANSFER_WRITE_BIT,                           //      VkMemoryOutputFlags     outputMask;
+                       VK_ACCESS_HOST_READ_BIT,                                        //      VkMemoryInputFlags      inputMask;
+                       queueFamilyIndex,                                                       //      deUint32                        srcQueueFamilyIndex;
+                       queueFamilyIndex,                                                       //      deUint32                        destQueueFamilyIndex;
+                       *readImageBuffer,                                                       //      VkBuffer                        buffer;
+                       0u,                                                                                     //      VkDeviceSize            offset;
+                       imageSizeBytes                                                          //      VkDeviceSize            size;
+               };
+               cpFinishBarriers.push_back(copyFinishBarrier);
+
+               if (needInterface)
+               {
+                       copyFinishBarrier.buffer        = *fragOutputBuffer;
+                       copyFinishBarrier.size          = VK_WHOLE_SIZE;
+                       cpFinishBarriers.push_back(copyFinishBarrier);
+
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 2, cpFinishBarriers.data(), 0, (const VkImageMemoryBarrier*)DE_NULL);
+               }
+               else
+               {
+                       vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, cpFinishBarriers.data(), 0, (const VkImageMemoryBarrier*)DE_NULL);
+               }
+       }
+
+       VK_CHECK(vk.endCommandBuffer(*cmdBuf));
+
+       // Upload vertex data
+       {
+               const VkMappedMemoryRange       range                   =
+               {
+                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
+                       DE_NULL,                                                                //      const void*             pNext;
+                       vertexBufferMemory->getMemory(),                //      VkDeviceMemory  mem;
+                       0,                                                                              //      VkDeviceSize    offset;
+                       (VkDeviceSize)sizeof(vertexData),               //      VkDeviceSize    size;
+               };
+               void*                                           vertexBufPtr    = vertexBufferMemory->getHostPtr();
+
+               deMemcpy(vertexBufPtr, &vertexData[0], sizeof(vertexData));
+               VK_CHECK(vk.flushMappedMemoryRanges(*vkDevice, 1u, &range));
+       }
+
+       if (needInterface)
+       {
+               const deUint32                          typNumBytes             = instance.interfaces.getInputType().getNumBytes();
+               const deUint32                          bufNumBytes             = static_cast<deUint32>(instance.interfaces.getInputBuffer()->getNumBytes());
+
+               // Require that the test instantation provides four output values.
+               DE_ASSERT(bufNumBytes == 4 * typNumBytes);
+
+               // We have four triangles. Because interpolation happens before executing the fragment shader,
+               // we need to provide the same vertex attribute for the same triangle. That means, duplicate each
+               // value three times for all four values.
+
+               const deUint8*                          provided                = static_cast<const deUint8*>(instance.interfaces.getInputBuffer()->data());
+               vector<deUint8>                         data;
+
+               data.reserve(3 * bufNumBytes);
+
+               for (deUint32 offset = 0; offset < bufNumBytes; offset += typNumBytes)
+                       for (deUint32 vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
+                               for (deUint32 byteNdx = 0; byteNdx < typNumBytes; ++byteNdx)
+                                       data.push_back(provided[offset + byteNdx]);
+
+               deMemcpy(vertexInputMemory->getHostPtr(), data.data(), data.size());
+
+               const VkMappedMemoryRange       range                   =
+               {
+                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
+                       DE_NULL,                                                                //      const void*             pNext;
+                       vertexInputMemory->getMemory(),                 //      VkDeviceMemory  mem;
+                       0,                                                                              //      VkDeviceSize    offset;
+                       VK_WHOLE_SIZE,                                                  //      VkDeviceSize    size;
+               };
+
+               VK_CHECK(vk.flushMappedMemoryRanges(*vkDevice, 1u, &range));
+       }
+
+       // Submit & wait for completion
+       {
+               const VkFenceCreateInfo fenceParams     =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    //      VkStructureType         sType;
+                       DE_NULL,                                                                //      const void*                     pNext;
+                       0u,                                                                             //      VkFenceCreateFlags      flags;
+               };
+               const Unique<VkFence>   fence           (createFence(vk, *vkDevice, &fenceParams));
+               const VkSubmitInfo              submitInfo      =
+               {
+                       VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                       DE_NULL,
+                       0u,
+                       (const VkSemaphore*)DE_NULL,
+                       (const VkPipelineStageFlags*)DE_NULL,
+                       1u,
+                       &cmdBuf.get(),
+                       0u,
+                       (const VkSemaphore*)DE_NULL,
+               };
+
+               VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
+               VK_CHECK(vk.waitForFences(*vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
+       }
+
+       const void* imagePtr    = readImageBufferMemory->getHostPtr();
+       const tcu::ConstPixelBufferAccess pixelBuffer(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
+                                                                                                 renderSize.x(), renderSize.y(), 1, imagePtr);
+       // Log image
+       {
+               const VkMappedMemoryRange       range           =
+               {
+                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
+                       DE_NULL,                                                                //      const void*             pNext;
+                       readImageBufferMemory->getMemory(),             //      VkDeviceMemory  mem;
+                       0,                                                                              //      VkDeviceSize    offset;
+                       imageSizeBytes,                                                 //      VkDeviceSize    size;
+               };
+
+               VK_CHECK(vk.invalidateMappedMemoryRanges(*vkDevice, 1u, &range));
+               context.getTestContext().getLog() << TestLog::Image("Result", "Result", pixelBuffer);
+       }
+
+       { // Make sure all output resources are ready.
+               for (deUint32 outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
+               {
+                       const VkMappedMemoryRange       range   =
+                       {
+                               VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,                  //      VkStructureType sType;
+                               DE_NULL,                                                                                //      const void*             pNext;
+                               outResourceMemories[outputNdx]->getMemory(),    //      VkDeviceMemory  mem;
+                               0,                                                                                              //      VkDeviceSize    offset;
+                               VK_WHOLE_SIZE,                                                                  //      VkDeviceSize    size;
+                       };
+
+                       VK_CHECK(vk.invalidateMappedMemoryRanges(*vkDevice, 1u, &range));
+               }
+       }
+
+       const RGBA threshold(1, 1, 1, 1);
+
+       const RGBA upperLeft(pixelBuffer.getPixel(1, 1));
+       if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold))
+               return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper left corner mismatch"));
+
+       const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1));
+       if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold))
+               return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper right corner mismatch"));
+
+       const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1));
+       if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold))
+               return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower left corner mismatch"));
+
+       const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1));
+       if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold))
+               return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower right corner mismatch"));
+
+       // Check that the contents in the ouput variable matches expected.
+       if (needInterface)
+       {
+               const IFDataType&                                       outputType                              = instance.interfaces.getOutputType();
+               const void*                                                     inputData                               = instance.interfaces.getInputBuffer()->data();
+               const void*                                                     outputData                              = instance.interfaces.getOutputBuffer()->data();
+               vector<std::pair<int, int> >            positions;
+               const tcu::ConstPixelBufferAccess       fragOutputBufferAccess  (outputType.getTextureFormat(), renderSize.x(), renderSize.y(), 1, fragOutputMemory->getHostPtr());
+
+               positions.push_back(std::make_pair(1, 1));
+               positions.push_back(std::make_pair(fragOutputBufferAccess.getWidth() - 1, 1));
+               positions.push_back(std::make_pair(1, fragOutputBufferAccess.getHeight() - 1));
+               positions.push_back(std::make_pair(fragOutputBufferAccess.getWidth() - 1, fragOutputBufferAccess.getHeight() - 1));
+
+               for (deUint32 posNdx = 0; posNdx < positions.size(); ++posNdx)
+               {
+                       const int       x               = positions[posNdx].first;
+                       const int       y               = positions[posNdx].second;
+                       bool            equal   = true;
+
+                       if (outputType.elementType == NUMBERTYPE_FLOAT32)
+                       {
+                               const float*            expected        = static_cast<const float*>(outputData) + posNdx * outputType.numElements;
+                               const float*            actual          = static_cast<const float*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (!compare32BitFloat(expected[eleNdx], actual[eleNdx], context.getTestContext().getLog()))
+                                               equal = false;
+                       }
+                       else if (outputType.elementType == NUMBERTYPE_INT32)
+                       {
+                               const deInt32*          expected        = static_cast<const deInt32*>(outputData) + posNdx * outputType.numElements;
+                               const deInt32*          actual          = static_cast<const deInt32*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (expected[eleNdx] != actual[eleNdx])
+                                               equal = false;
+                       }
+                       else if (outputType.elementType == NUMBERTYPE_UINT32)
+                       {
+                               const deUint32*         expected        = static_cast<const deUint32*>(outputData) + posNdx * outputType.numElements;
+                               const deUint32*         actual          = static_cast<const deUint32*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (expected[eleNdx] != actual[eleNdx])
+                                               equal = false;
+                       }
+                       else if (outputType.elementType == NUMBERTYPE_FLOAT16)
+                       {
+                               const float*            original        = static_cast<const float*>(inputData) + posNdx * outputType.numElements;
+                               const deFloat16*        actual          = static_cast<const deFloat16*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (!compare16BitFloat(original[eleNdx], actual[eleNdx], instance.interfaces.getRoundingMode(), context.getTestContext().getLog()))
+                                               equal = false;
+                       }
+                       else if (outputType.elementType == NUMBERTYPE_INT16)
+                       {
+                               const deInt16*          expected        = static_cast<const deInt16*>(outputData) + posNdx * outputType.numElements;
+                               const deInt16*          actual          = static_cast<const deInt16*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (expected[eleNdx] != actual[eleNdx])
+                                               equal = false;
+                       }
+                       else if (outputType.elementType == NUMBERTYPE_UINT16)
+                       {
+                               const deUint16*         expected        = static_cast<const deUint16*>(outputData) + posNdx * outputType.numElements;
+                               const deUint16*         actual          = static_cast<const deUint16*>(fragOutputBufferAccess.getPixelPtr(x, y));
+
+                               for (deUint32 eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
+                                       if (expected[eleNdx] != actual[eleNdx])
+                                               equal = false;
+                       }
+                       else {
+                               DE_ASSERT(0 && "unhandled type");
+                       }
+
+                       if (!equal)
+                               return TestStatus(instance.failResult, instance.getSpecializedFailMessage("fragment output dat point #" + numberToString(posNdx) + " mismatch"));
+               }
+       }
+
+       // Check the contents in output resources match with expected.
+       for (deUint32 outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
+       {
+               const BufferSp& expected = instance.resources.outputs[outputNdx].second;
+
+               if (instance.resources.verifyIO != DE_NULL)
+               {
+                       if (!(*instance.resources.verifyIO)(instance.resources.inputs, outResourceMemories, instance.resources.outputs, context.getTestContext().getLog()))
+                               return tcu::TestStatus::fail("Resource returned doesn't match with expected");
+               }
+               else
+               {
+                       if (deMemCmp(expected->data(), outResourceMemories[outputNdx]->getHostPtr(), expected->getNumBytes()))
+                               return tcu::TestStatus::fail("Resource returned doesn't match bitwisely with expected");
+               }
+       }
+
+       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,
+                                                         const vector<deInt32>&                specConstants,
+                                                         const PushConstants&                  pushConstants,
+                                                         const GraphicsResources&              resources,
+                                                         const GraphicsInterfaces&             interfaces,
+                                                         const vector<string>&                 extensions,
+                                                         const vector<string>&                 features,
+                                                         ExtensionFeatures                             extensionFeatures,
+                                                         tcu::TestCaseGroup*                   tests,
+                                                         const qpTestResult                    failResult,
+                                                         const string&                                 failMessageTemplate)
+{
+       const ShaderElement             vertFragPipelineStages[]                =
+       {
+               ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
+               ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
+       };
+
+       const ShaderElement             tessPipelineStages[]                    =
+       {
+               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("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
+       };
+
+       const ShaderElement             geomPipelineStages[]                            =
+       {
+               ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
+               ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
+               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(vertFragPipelineStages, inputColors, outputColors, testCodeFragments,
+                               specConstantMap, pushConstants, resources, interfaces, extensions, features, extensionFeatures, failResult, failMessageTemplate));
+
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants;
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       tests, name + "_tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
+                       createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments,
+                               specConstantMap, pushConstants, resources, interfaces, extensions, features, extensionFeatures, failResult, failMessageTemplate));
+
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants;
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       tests, name + "_tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
+                       createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments,
+                               specConstantMap, pushConstants, resources, interfaces, extensions, features, extensionFeatures, failResult, failMessageTemplate));
+
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants;
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       tests, name + "_geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
+                       createInstanceContext(geomPipelineStages, inputColors, outputColors, testCodeFragments,
+                               specConstantMap, pushConstants, resources, interfaces, extensions, features, extensionFeatures, failResult, failMessageTemplate));
+
+       specConstantMap.clear();
+       specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants;
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       tests, name + "_frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
+                       createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments,
+                               specConstantMap, pushConstants, resources, interfaces, extensions, features, extensionFeatures, failResult, failMessageTemplate));
+}
+
+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("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
+       };
+
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       group, name, "", addShaderCodeCustomTessControl,
+                       runAndVerifyDefaultPipeline, createInstanceContext(
+                               pipelineStages, defaultColors, defaultColors, fragments,
+                               StageToSpecConstantMap(), PushConstants(), GraphicsResources(),
+                               GraphicsInterfaces(), vector<string>(), vector<string>(),
+                               ExtensionFeatures()));
+}
+
+} // SpirVAssembly
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmGraphicsShaderTestUtil.hpp
new file mode 100644 (file)
index 0000000..1f0f020
--- /dev/null
@@ -0,0 +1,553 @@
+#ifndef _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP
+#define _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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 Graphics pipeline and helper functions for SPIR-V assembly tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuCommandLine.hpp"
+#include "tcuRGBA.hpp"
+
+#include "vkPrograms.hpp"
+#include "vktSpvAsmComputeShaderTestUtil.hpp"
+#include "vktSpvAsmUtils.hpp"
+#include "vktTestCaseUtil.hpp"
+
+#include "deRandom.hpp"
+#include "deSharedPtr.hpp"
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+typedef vk::Unique<VkBuffer>                                                                           BufferHandleUp;
+typedef de::SharedPtr<BufferHandleUp>                                                          BufferHandleSp;
+typedef vk::Unique<vk::VkShaderModule>                                                         ModuleHandleUp;
+typedef de::SharedPtr<ModuleHandleUp>                                                          ModuleHandleSp;
+typedef std::pair<std::string, vk::VkShaderStageFlagBits>                      EntryToStage;
+typedef std::map<std::string, std::vector<EntryToStage> >                      ModuleMap;
+typedef std::map<vk::VkShaderStageFlagBits, std::vector<deInt32> >     StageToSpecConstantMap;
+typedef std::pair<vk::VkDescriptorType, BufferSp>                                      Resource;
+
+enum NumberType
+{
+       NUMBERTYPE_INT32,
+       NUMBERTYPE_UINT32,
+       NUMBERTYPE_FLOAT32,
+       NUMBERTYPE_END32,               // Marks the end of 32-bit scalar types
+       NUMBERTYPE_INT16,
+       NUMBERTYPE_UINT16,
+       NUMBERTYPE_FLOAT16,
+};
+
+typedef enum RoundingModeFlags_e
+{
+       ROUNDINGMODE_RTE = 0x1, // Round to nearest even
+       ROUNDINGMODE_RTZ = 0x2, // Round to zero
+} RoundingModeFlags;
+
+typedef bool (*GraphicsVerifyIOFunc) (const std::vector<Resource>&             inputs,
+                                                                         const std::vector<AllocationSp>&      outputAllocations,
+                                                                         const std::vector<Resource>&          expectedOutputs,
+                                                                         tcu::TestLog&                                         log);
+
+// Resources used by graphics-pipeline-based tests.
+struct GraphicsResources
+{
+       // Resources used as inputs.
+       std::vector<Resource>   inputs;
+       // Resources used as outputs. The data supplied will be used as
+       // the expected outputs for the corresponding bindings by default.
+       // If other behaviors are needed, please provide a custom verifyIO.
+       std::vector<Resource>   outputs;
+       // 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.
+       GraphicsVerifyIOFunc    verifyIO;
+
+                                                       GraphicsResources()
+                                                               : verifyIO      (DE_NULL)
+                                                       {}
+};
+
+// Interface data type.
+struct IFDataType
+{
+                                               IFDataType                      (deUint32 numE, NumberType elementT)
+                                                       : numElements   (numE)
+                                                       , elementType   (elementT)
+                                               {
+                                                       DE_ASSERT(numE > 0 && numE < 5);
+                                                       DE_ASSERT(elementT != NUMBERTYPE_END32);
+                                               }
+
+                                               IFDataType                      (const IFDataType& that)
+                                                       : numElements   (that.numElements)
+                                                       , elementType   (that.elementType)
+                                               {}
+
+       deUint32                        getElementNumBytes      (void) const;
+       deUint32                        getNumBytes                     (void) const { return numElements * getElementNumBytes(); }
+
+       vk::VkFormat            getVkFormat                     (void) const;
+
+       tcu::TextureFormat      getTextureFormat        (void) const;
+
+       std::string                     str                                     (void) const;
+
+       bool                            elementIs32bit          (void) const { return elementType < NUMBERTYPE_END32; }
+       bool                            isVector                        (void) const { return numElements > 1; }
+
+       deUint32                        numElements;
+       NumberType                      elementType;
+};
+
+typedef std::pair<IFDataType, BufferSp>                        Interface;
+
+// Interface variables used by graphics-pipeline-based tests.
+class GraphicsInterfaces
+{
+public:
+                                               GraphicsInterfaces      ()
+                                                       : rndMode       (static_cast<RoundingModeFlags>(0))
+                                               {}
+
+                                               GraphicsInterfaces      (const GraphicsInterfaces& that)
+                                                       : inputs        (that.inputs)
+                                                       , outputs       (that.outputs)
+                                                       , rndMode       (that.rndMode)
+                                               {}
+
+       void                            setInputOutput          (const Interface& input, const Interface&  output)
+                                               {
+                                                       inputs.clear();
+                                                       outputs.clear();
+                                                       inputs.push_back(input);
+                                                       outputs.push_back(output);
+                                               }
+
+       const IFDataType&       getInputType            (void) const
+                                               {
+                                                       DE_ASSERT(inputs.size() == 1);
+                                                       return inputs.front().first;
+                                               }
+
+       const IFDataType&       getOutputType           (void) const
+                                               {
+                                                       DE_ASSERT(outputs.size() == 1);
+                                                       return outputs.front().first;
+                                               }
+
+       const BufferSp&         getInputBuffer          (void) const
+                                               {
+                                                       DE_ASSERT(inputs.size() == 1);
+                                                       return inputs.front().second;
+                                               }
+
+       const BufferSp&         getOutputBuffer         (void) const
+                                               {
+                                                       DE_ASSERT(outputs.size() == 1);
+                                                       return outputs.front().second;
+                                               }
+
+       bool                            empty                           (void) const
+                                               {
+                                                       return inputs.size() == 0;
+                                               }
+
+       void                            setRoundingMode         (RoundingModeFlags flag)
+                                               {
+                                                       rndMode = flag;
+                                               }
+       RoundingModeFlags       getRoundingMode         (void) const
+                                               {
+                                                       return rndMode;
+                                               }
+private:
+       // vector<Interface> acts as a null-able Interface here. Canonically we should use
+       // std::unique_ptr, but sadly we cannot leverage C++11 in dEQP. dEQP has its own
+       // de::UniquePtr, but still cumbersome to use in InstanceContext and do copies
+       // at various places.
+       // Public methods should make sure that there are less than two elements in both
+       // members and both members have the same number of elements.
+       std::vector<Interface>  inputs;
+       std::vector<Interface>  outputs;
+       RoundingModeFlags               rndMode;
+
+};
+
+struct PushConstants
+{
+public:
+                                                       PushConstants (void)
+                                                       {}
+
+                                                       PushConstants (const PushConstants& that)
+                                                               : pcs   (that.pcs)
+                                                       {}
+
+       void                                    setPushConstant (const BufferSp& pc)
+                                                       {
+                                                               pcs.clear();
+                                                               pcs.push_back(pc);
+                                                       }
+
+       bool                                    empty (void) const
+                                                       {
+                                                               return pcs.empty();
+                                                       }
+
+       const BufferSp&                 getBuffer(void) const
+                                                       {
+                                                               DE_ASSERT(pcs.size() == 1);
+                                                               return pcs[0];
+                                                       }
+
+private:
+       // Right now we only support one field in the push constant block.
+       std::vector<BufferSp>   pcs;
+};
+
+// Returns the corresponding buffer usage flag bit for the given descriptor type.
+VkBufferUsageFlagBits getMatchingBufferUsageFlagBit(VkDescriptorType dType);
+
+// Context for a specific test instantiation. For example, an instantiation
+// may test colors yellow/magenta/cyan/mauve in a tesselation shader
+// with an entry point named 'main_to_the_main'
+struct InstanceContext
+{
+       // Map of modules to what entry_points we care to use from those modules.
+       ModuleMap                                                               moduleMap;
+       tcu::RGBA                                                               inputColors[4];
+       tcu::RGBA                                                               outputColors[4];
+       // Concrete SPIR-V code to test via boilerplate specialization.
+       std::map<std::string, std::string>              testCodeFragments;
+       StageToSpecConstantMap                                  specConstants;
+       bool                                                                    hasTessellation;
+       vk::VkShaderStageFlagBits                               requiredStages;
+       std::vector<std::string>                                requiredDeviceExtensions;
+       std::vector<std::string>                                requiredDeviceFeatures;
+       ExtensionFeatures                                               requestedExtensionFeatures;
+       PushConstants                                                   pushConstants;
+       // Possible resources used by the graphics pipeline.
+       // If it is not empty, a single descriptor set (number 0) will be allocated
+       // to point to all resources specified. Binding numbers are allocated in
+       // accord with the resources' order in the vector; outputs are allocated
+       // after inputs.
+       GraphicsResources                                               resources;
+       // Possible interface variables use by the graphics pipeline.
+       // If it is not empty, input/output variables will be set up for shader stages
+       // in the test. Both the input and output variable will take location #2 in the
+       // pipeline for all stages, except that the output variable in the fragment
+       // stage will take location #1.
+       GraphicsInterfaces                                              interfaces;
+       qpTestResult                                                    failResult;
+       std::string                                                             failMessageTemplate;    //!< ${reason} in the template will be replaced with a detailed failure message
+
+       InstanceContext (const tcu::RGBA                                                        (&inputs)[4],
+                                        const tcu::RGBA                                                        (&outputs)[4],
+                                        const std::map<std::string, std::string>&      testCodeFragments_,
+                                        const StageToSpecConstantMap&                          specConstants_,
+                                        const PushConstants&                                           pushConsants_,
+                                        const GraphicsResources&                                       resources_,
+                                        const GraphicsInterfaces&                                      interfaces_,
+                                        const std::vector<std::string>&                        extensions_,
+                                        const std::vector<std::string>&                        features_,
+                                        ExtensionFeatures                                                      extFeatures_);
+
+       InstanceContext (const InstanceContext& other);
+
+       std::string getSpecializedFailMessage (const std::string& failureReason);
+};
+
+// A description of a shader to be used for a single stage of the graphics pipeline.
+struct ShaderElement
+{
+       // The module that contains this shader entrypoint.
+       std::string                                     moduleName;
+
+       // The name of the entrypoint.
+       std::string                                     entryName;
+
+       // Which shader stage this entry point represents.
+       vk::VkShaderStageFlagBits       stage;
+
+       ShaderElement (const std::string& moduleName_, const std::string& entryPoint_, vk::VkShaderStageFlagBits shaderStage_);
+};
+
+template <typename T>
+const std::string numberToString (T number)
+{
+       std::stringstream ss;
+       ss << number;
+       return ss.str();
+}
+
+// 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;
+}
+
+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);        }
+
+
+void getDefaultColors (tcu::RGBA (&colors)[4]);
+
+void getHalfColorsFullAlpha (tcu::RGBA (&colors)[4]);
+
+void getInvertedDefaultColors (tcu::RGBA (&colors)[4]);
+
+// Creates fragments that specialize into a simple pass-through shader (of any kind).
+std::map<std::string, std::string> passthruFragments(void);
+
+void createCombinedModule(vk::SourceCollections& dst, InstanceContext);
+
+// This has two shaders of each stage. The first
+// is a passthrough, the second inverts the color.
+void createMultipleEntries(vk::SourceCollections& dst, InstanceContext);
+
+// 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 tcu::RGBA                                                              (&inputColors)[4],
+                                                                          const tcu::RGBA                                                              (&outputColors)[4],
+                                                                          const std::map<std::string, std::string>&    testCodeFragments,
+                                                                          const StageToSpecConstantMap&                                specConstants,
+                                                                          const PushConstants&                                                 pushConstants,
+                                                                          const GraphicsResources&                                             resources,
+                                                                          const GraphicsInterfaces&                                    interfaces,
+                                                                          const std::vector<std::string>&                              extensions,
+                                                                          const std::vector<std::string>&                              features,
+                                                                          ExtensionFeatures                                                    extensionFeatures,
+                                                                          const qpTestResult                                                   failResult                      = QP_TEST_RESULT_FAIL,
+                                                                          const std::string&                                                   failMessageTemplate     = std::string())
+{
+       InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants, pushConstants, resources, interfaces, extensions, features, extensionFeatures);
+       for (size_t i = 0; i < N; ++i)
+       {
+               ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
+               ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
+       }
+       ctx.failResult                          = failResult;
+       if (!failMessageTemplate.empty())
+               ctx.failMessageTemplate = failMessageTemplate;
+       return ctx;
+}
+
+// The same as createInstanceContext above, without extensions, spec constants, and resources.
+template<size_t N>
+inline InstanceContext createInstanceContext (const ShaderElement                                              (&elements)[N],
+                                                                                         tcu::RGBA                                                                     (&inputColors)[4],
+                                                                                         const tcu::RGBA                                                       (&outputColors)[4],
+                                                                                         const std::map<std::string, std::string>&     testCodeFragments)
+{
+       return createInstanceContext(elements, inputColors, outputColors, testCodeFragments,
+                                                                StageToSpecConstantMap(), PushConstants(), GraphicsResources(),
+                                                                GraphicsInterfaces(), std::vector<std::string>(), std::vector<std::string>(),
+                                                                ExtensionFeatures());
+}
+
+// The same as createInstanceContext above, but with default colors.
+template<size_t N>
+InstanceContext createInstanceContext (const ShaderElement                                                     (&elements)[N],
+                                                                          const std::map<std::string, std::string>&    testCodeFragments)
+{
+       tcu::RGBA defaultColors[4];
+       getDefaultColors(defaultColors);
+       return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
+}
+
+
+void createTestsForAllStages (const std::string&                                               name,
+                                                         const tcu::RGBA                                                       (&inputColors)[4],
+                                                         const tcu::RGBA                                                       (&outputColors)[4],
+                                                         const std::map<std::string, std::string>&     testCodeFragments,
+                                                         const std::vector<deInt32>&                           specConstants,
+                                                         const PushConstants&                                          pushConstants,
+                                                         const GraphicsResources&                                      resources,
+                                                         const GraphicsInterfaces&                                     interfaces,
+                                                         const std::vector<std::string>&                       extensions,
+                                                         const std::vector<std::string>&                       features,
+                                                         ExtensionFeatures                                                     extensionFeatures,
+                                                         tcu::TestCaseGroup*                                           tests,
+                                                         const qpTestResult                                            failResult                      = QP_TEST_RESULT_FAIL,
+                                                         const std::string&                                            failMessageTemplate     = std::string());
+
+inline void createTestsForAllStages (const std::string&                                                        name,
+                                                                        const tcu::RGBA                                                        (&inputColors)[4],
+                                                                        const tcu::RGBA                                                        (&outputColors)[4],
+                                                                        const std::map<std::string, std::string>&      testCodeFragments,
+                                                                        tcu::TestCaseGroup*                                            tests,
+                                                                        const qpTestResult                                                     failResult                      = QP_TEST_RESULT_FAIL,
+                                                                        const std::string&                                                     failMessageTemplate     = std::string())
+{
+       std::vector<deInt32>            noSpecConstants;
+       PushConstants                           noPushConstants;
+       GraphicsResources                       noResources;
+       GraphicsInterfaces                      noInterfaces;
+       std::vector<std::string>        noExtensions;
+       std::vector<std::string>        noFeatures;
+
+       createTestsForAllStages(
+                       name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
+                       noResources, noInterfaces, noExtensions, noFeatures, ExtensionFeatures(),
+                       tests, failResult, failMessageTemplate);
+}
+
+inline void createTestsForAllStages (const std::string&                                                        name,
+                                                                        const tcu::RGBA                                                        (&inputColors)[4],
+                                                                        const tcu::RGBA                                                        (&outputColors)[4],
+                                                                        const std::map<std::string, std::string>&      testCodeFragments,
+                                                                        const std::vector<deInt32>&                            specConstants,
+                                                                        tcu::TestCaseGroup*                                            tests,
+                                                                        const qpTestResult                                                     failResult                      = QP_TEST_RESULT_FAIL,
+                                                                        const std::string&                                                     failMessageTemplate     = std::string())
+{
+       PushConstants                                   noPushConstants;
+       GraphicsResources                               noResources;
+       GraphicsInterfaces                              noInterfaces;
+       std::vector<std::string>                noExtensions;
+       std::vector<std::string>                noFeatures;
+
+       createTestsForAllStages(
+                       name, inputColors, outputColors, testCodeFragments, specConstants, noPushConstants,
+                       noResources, noInterfaces, noExtensions, noFeatures, ExtensionFeatures(),
+                       tests, failResult, failMessageTemplate);
+}
+
+inline void createTestsForAllStages (const std::string&                                                        name,
+                                                                        const tcu::RGBA                                                        (&inputColors)[4],
+                                                                        const tcu::RGBA                                                        (&outputColors)[4],
+                                                                        const std::map<std::string, std::string>&      testCodeFragments,
+                                                                        const GraphicsResources&                                       resources,
+                                                                        const std::vector<std::string>&                        extensions,
+                                                                        tcu::TestCaseGroup*                                            tests,
+                                                                        ExtensionFeatures                                                      extensionFeatures       = ExtensionFeatures(),
+                                                                        const qpTestResult                                                     failResult                      = QP_TEST_RESULT_FAIL,
+                                                                        const std::string&                                                     failMessageTemplate     = std::string())
+{
+       std::vector<deInt32>            noSpecConstants;
+       PushConstants                           noPushConstants;
+       GraphicsInterfaces                      noInterfaces;
+       std::vector<std::string>        noFeatures;
+
+       createTestsForAllStages(
+                       name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
+                       resources, noInterfaces, extensions, noFeatures, extensionFeatures,
+                       tests, failResult, failMessageTemplate);
+}
+
+inline void createTestsForAllStages (const std::string& name,
+                                                                        const tcu::RGBA                                                        (&inputColors)[4],
+                                                                        const tcu::RGBA                                                        (&outputColors)[4],
+                                                                        const std::map<std::string, std::string>&      testCodeFragments,
+                                                                        const GraphicsInterfaces                                       interfaces,
+                                                                        const std::vector<std::string>&                        extensions,
+                                                                        tcu::TestCaseGroup*                                            tests,
+                                                                        ExtensionFeatures                                                      extensionFeatures       = ExtensionFeatures(),
+                                                                        const qpTestResult                                                     failResult                      = QP_TEST_RESULT_FAIL,
+                                                                        const std::string&                                                     failMessageTemplate     = std::string())
+{
+       GraphicsResources                       noResources;
+       std::vector<deInt32>            noSpecConstants;
+       std::vector<std::string>        noFeatures;
+       PushConstants                           noPushConstants;
+
+       createTestsForAllStages(
+                       name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
+                       noResources, interfaces, extensions, noFeatures, extensionFeatures,
+                       tests, failResult, failMessageTemplate);
+}
+
+inline void createTestsForAllStages (const std::string& name,
+                                                                        const tcu::RGBA                                                        (&inputColors)[4],
+                                                                        const tcu::RGBA                                                        (&outputColors)[4],
+                                                                        const std::map<std::string, std::string>&      testCodeFragments,
+                                                                        const PushConstants&                                           pushConstants,
+                                                                        const GraphicsResources&                                       resources,
+                                                                        const std::vector<std::string>&                        extensions,
+                                                                        tcu::TestCaseGroup*                                            tests,
+                                                                        ExtensionFeatures                                                      extensionFeatures       = ExtensionFeatures(),
+                                                                        const qpTestResult                                                     failResult                      = QP_TEST_RESULT_FAIL,
+                                                                        const std::string&                                                     failMessageTemplate     = std::string())
+{
+       std::vector<deInt32>                    noSpecConstants;
+       GraphicsInterfaces                              noInterfaces;
+       std::vector<std::string>                noFeatures;
+
+       createTestsForAllStages(
+                       name, inputColors, outputColors, testCodeFragments, noSpecConstants, pushConstants,
+                       resources, noInterfaces, extensions, noFeatures, extensionFeatures,
+                       tests, failResult, failMessageTemplate);
+}
+
+// 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
+// whatever the shaders draw can be directly spot-checked.
+tcu::TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance);
+
+// 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 std::map<std::string, std::string>& fragments);
+
+// Given the original 32-bit float value, computes the corresponding 16-bit
+// float value under the given rounding mode flags and compares with the
+// returned 16-bit float value. Returns true if they are considered as equal.
+//
+// The following equivalence criteria are respected:
+// * Positive and negative zeros are considered equivalent.
+// * Denormalized floats are allowed to be flushed to zeros.
+// * Different bit patterns of NaNs are allowed.
+// * For the rest, require exactly the same bit pattern.
+bool compare16BitFloat (float original, deUint16 returned, RoundingModeFlags flags, tcu::TestLog& log);
+
+// Compare the returned 32-bit float against its expected value.
+//
+// The following equivalence criteria are respected:
+// * Denormalized floats are allowed to be flushed to zeros.
+// * Different bit patterns of NaNs/Infs are allowed.
+// * For the rest, use C++ float equivalence check.
+bool compare32BitFloat (float expected, float returned, tcu::TestLog& log);
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP
index 5aafc4b..d253359 100644 (file)
@@ -3,6 +3,7 @@
  * ------------------------
  *
  * Copyright (c) 2015 Google Inc.
+ * Copyright (c) 2016 The Khronos Group Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -49,6 +50,7 @@
 
 #include "vktSpvAsmComputeShaderCase.hpp"
 #include "vktSpvAsmComputeShaderTestUtil.hpp"
+#include "vktSpvAsmGraphicsShaderTestUtil.hpp"
 #include "vktTestCaseUtil.hpp"
 
 #include <cmath>
@@ -56,6 +58,7 @@
 #include <map>
 #include <string>
 #include <sstream>
+#include <utility>
 
 namespace vkt
 {
@@ -79,13 +82,6 @@ using de::UniquePtr;
 using tcu::StringTemplate;
 using tcu::Vec4;
 
-typedef Unique<VkShaderModule>                 ModuleHandleUp;
-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<typename T>
 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
 {
@@ -94,6 +90,22 @@ static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* ds
                typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
 }
 
+// Filter is a function that returns true if a value should pass, false otherwise.
+template<typename T, typename FilterT>
+static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, FilterT filter, int offset = 0)
+{
+       T* const typedPtr = (T*)dst;
+       T value;
+       for (int ndx = 0; ndx < numValues; ndx++)
+       {
+               do
+                       value = randomScalar<T>(rnd, minValue, maxValue);
+               while (!filter(value));
+
+               typedPtr[offset + ndx] = value;
+       }
+}
+
 static void floorAll (vector<float>& values)
 {
        for (size_t i = 0; i < values.size(); i++)
@@ -132,45 +144,6 @@ struct CaseParameter
 //   output_data.elements[x] = -input_data.elements[x];
 // }
 
-static const char* const s_ShaderPreamble =
-       "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 =
-       "%bool      = OpTypeBool\n"
-       "%void      = OpTypeVoid\n"
-       "%voidf     = OpTypeFunction %void\n"
-       "%u32       = OpTypeInt 32 0\n"
-       "%i32       = OpTypeInt 32 1\n"
-       "%f32       = OpTypeFloat 32\n"
-       "%uvec3     = OpTypeVector %u32 3\n"
-       "%fvec3     = OpTypeVector %f32 3\n"
-       "%uvec3ptr  = OpTypePointer Input %uvec3\n"
-       "%i32ptr    = OpTypePointer Uniform %i32\n"
-       "%f32ptr    = OpTypePointer Uniform %f32\n"
-       "%i32arr    = OpTypeRuntimeArray %i32\n"
-       "%f32arr    = OpTypeRuntimeArray %f32\n";
-
-// Declares two uniform variables (indata, outdata) of type "struct { float[] }". Depends on type "f32arr" (for "float[]").
-static const char* const s_InputOutputBuffer =
-       "%buf     = OpTypeStruct %f32arr\n"
-       "%bufptr  = OpTypePointer Uniform %buf\n"
-       "%indata    = OpVariable %bufptr Uniform\n"
-       "%outdata   = OpVariable %bufptr Uniform\n";
-
-// 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 %buf BufferBlock\n"
-       "OpDecorate %indata DescriptorSet 0\n"
-       "OpDecorate %indata Binding 0\n"
-       "OpDecorate %outdata DescriptorSet 0\n"
-       "OpDecorate %outdata Binding 1\n"
-       "OpDecorate %f32arr ArrayStride 4\n"
-       "OpMemberDecorate %buf 0 Offset 0\n";
-
 tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opnop", "Test the OpNop instruction"));
@@ -186,7 +159,7 @@ tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
                negativeFloats[ndx] = -positiveFloats[ndx];
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -194,9 +167,9 @@ tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes)
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes())
 
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -276,7 +249,7 @@ tcu::TestCaseGroup* createOpFUnordGroup (tcu::TestContext& testCtx)
 
        const StringTemplate                    shaderTemplate  (
 
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -297,7 +270,7 @@ tcu::TestCaseGroup* createOpFUnordGroup (tcu::TestContext& testCtx)
                "OpMemberDecorate %buf 0 Offset 0\n"
                "OpMemberDecorate %buf2 0 Offset 0\n"
 
-               + string(s_CommonTypes) +
+               + string(getComputeAsmCommonTypes()) +
 
                "%buf        = OpTypeStruct %f32arr\n"
                "%bufptr     = OpTypePointer Uniform %buf\n"
@@ -399,7 +372,7 @@ tcu::TestCaseGroup* createOpAtomicGroup (tcu::TestContext& testCtx)
 
        const StringTemplate                    shaderTemplate  (
 
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -419,7 +392,7 @@ tcu::TestCaseGroup* createOpAtomicGroup (tcu::TestContext& testCtx)
                "OpMemberDecorate %sumbuf 0 Coherent\n"
                "OpMemberDecorate %sumbuf 0 Offset 0\n"
 
-               + string(s_CommonTypes) +
+               + string(getComputeAsmCommonTypes()) +
 
                "%buf       = OpTypeStruct %i32arr\n"
                "%bufptr    = OpTypePointer Uniform %buf\n"
@@ -514,7 +487,7 @@ tcu::TestCaseGroup* createOpLineGroup (tcu::TestContext& testCtx)
                negativeFloats[ndx] = -positiveFloats[ndx];
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "%fname1 = OpString \"negateInputs.comp\"\n"
                "%fname2 = OpString \"negateInputs\"\n"
@@ -525,11 +498,11 @@ tcu::TestCaseGroup* createOpLineGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) +
+               + string(getComputeAsmInputOutputBufferTraits()) +
 
                "OpLine %fname1 0 0\n" // At the earliest possible position
 
-               + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "OpLine %fname1 0 1\n" // Multiple OpLines in sequence
                "OpLine %fname2 1 0\n" // Different filenames
@@ -578,7 +551,7 @@ tcu::TestCaseGroup* createOpNoLineGroup (tcu::TestContext& testCtx)
                negativeFloats[ndx] = -positiveFloats[ndx];
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "%fname = OpString \"negateInputs.comp\"\n"
 
@@ -588,11 +561,11 @@ tcu::TestCaseGroup* createOpNoLineGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) +
+               + string(getComputeAsmInputOutputBufferTraits()) +
 
                "OpNoLine\n" // At the earliest possible position, without preceding OpLine
 
-               + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "OpLine %fname 0 1\n"
                "OpNoLine\n" // Immediately following a preceding OpLine
@@ -659,7 +632,7 @@ tcu::TestCaseGroup* createNoContractionGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats2    (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -678,7 +651,7 @@ tcu::TestCaseGroup* createNoContractionGroup (tcu::TestContext& testCtx)
                "OpDecorate %f32arr ArrayStride 4\n"
                "OpMemberDecorate %buf 0 Offset 0\n"
 
-               + string(s_CommonTypes) +
+               + string(getComputeAsmCommonTypes()) +
 
                "%buf        = OpTypeStruct %f32arr\n"
                "%bufptr     = OpTypePointer Uniform %buf\n"
@@ -786,7 +759,7 @@ tcu::TestCaseGroup* createOpFRemGroup (tcu::TestContext& testCtx)
        }
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -803,7 +776,7 @@ tcu::TestCaseGroup* createOpFRemGroup (tcu::TestContext& testCtx)
                "OpDecorate %f32arr ArrayStride 4\n"
                "OpMemberDecorate %buf 0 Offset 0\n"
 
-               + string(s_CommonTypes) +
+               + string(getComputeAsmCommonTypes()) +
 
                "%buf        = OpTypeStruct %f32arr\n"
                "%bufptr     = OpTypePointer Uniform %buf\n"
@@ -860,7 +833,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
 
        spec1.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -868,7 +841,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
                "OpDecorate %vec4arr ArrayStride 16\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%vec4       = OpTypeVector %f32 4\n"
                "%vec4ptr_u  = OpTypePointer Uniform %vec4\n"
@@ -918,7 +891,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                outputFloats2[ndx] = inputFloats2[ndx];
 
        spec2.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -926,7 +899,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
                "OpDecorate %f32arr100 ArrayStride 4\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%hundred        = OpConstant %u32 100\n"
                "%f32arr100      = OpTypeArray %f32 %hundred\n"
@@ -967,7 +940,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                outputFloats3[ndx] = inputFloats3[ndx];
 
        spec3.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -978,7 +951,7 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                "OpMemberDecorate %buf 2 Offset 32\n"
                "OpMemberDecorate %buf 3 Offset 48\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%vec4      = OpTypeVector %f32 4\n"
                "%buf       = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
@@ -1015,14 +988,14 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
                outputFloats4[ndx] = -inputFloats4[ndx];
 
        spec4.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%f32ptr_f  = OpTypePointer Function %f32\n"
                "%id        = OpVariable %uvec3ptr Input\n"
@@ -1069,21 +1042,21 @@ tcu::TestCaseGroup* createOpCopyObjectGroup (tcu::TestContext& testCtx)
                outputFloats[ndx] = inputFloats[ndx] + 7.5f;
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%fmat     = OpTypeMatrix %fvec3 3\n"
                "%three    = OpConstant %u32 3\n"
                "%farr     = OpTypeArray %f32 %three\n"
                "%fst      = OpTypeStruct %f32 %f32\n"
 
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBuffer()) +
 
                "%id            = OpVariable %uvec3ptr Input\n"
                "%zero          = OpConstant %i32 0\n"
@@ -1182,7 +1155,7 @@ tcu::TestCaseGroup* createOpUnreachableGroup (tcu::TestContext& testCtx)
                negativeFloats[ndx] = -positiveFloats[ndx];
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main            \"main\"\n"
@@ -1193,7 +1166,7 @@ tcu::TestCaseGroup* createOpUnreachableGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%u32ptr    = OpTypePointer Function %u32\n"
                "%uintfuint = OpTypeFunction %u32 %u32ptr\n"
@@ -1209,7 +1182,7 @@ tcu::TestCaseGroup* createOpUnreachableGroup (tcu::TestContext& testCtx)
                "%hundred   = OpConstant %u32 100\n"
                "%thousand  = OpConstant %u32 1000\n"
 
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBuffer()) +
 
                // Main()
                "%main   = OpFunction %void None %voidf\n"
@@ -1336,7 +1309,7 @@ tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
                outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -1388,7 +1361,7 @@ tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
                "OpGroupDecorate %group3 %indata4\n"
                "OpDecorate %indata4 Binding 4\n"
 
-               + string(s_CommonTypes) +
+               + string(getComputeAsmCommonTypes()) +
 
                "%id   = OpVariable %uvec3ptr Input\n"
                "%zero = OpConstant %i32 0\n"
@@ -1491,7 +1464,7 @@ tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
        vector<deInt32>                                 outputInts3             (numElements, 0);
        vector<deInt32>                                 outputInts4             (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -1501,7 +1474,7 @@ tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
                "OpDecorate %sc_1  SpecId 1\n"
                "OpDecorate %i32arr ArrayStride 4\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%buf     = OpTypeStruct %i32arr\n"
                "%bufptr  = OpTypePointer Uniform %buf\n"
@@ -1598,7 +1571,7 @@ tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
        ComputeShaderSpec                               spec;
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -1609,7 +1582,7 @@ tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
                "OpDecorate %sc_2  SpecId 2\n"
                "OpDecorate %i32arr ArrayStride 4\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%ivec3     = OpTypeVector %i32 3\n"
                "%buf     = OpTypeStruct %i32arr\n"
@@ -1690,7 +1663,7 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
        }
 
        spec1.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -1698,7 +1671,7 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id = OpVariable %uvec3ptr Input\n"
                "%zero       = OpConstant %i32 0\n"
@@ -1750,14 +1723,14 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
        group->addChild(new SpvAsmComputeShaderCase(testCtx, "block", "out-of-order and unreachable blocks for OpPhi", spec1));
 
        spec2.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main \"main\"\n"
                "OpName %id \"gl_GlobalInvocationID\"\n"
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id         = OpVariable %uvec3ptr Input\n"
                "%zero       = OpConstant %i32 0\n"
@@ -1794,14 +1767,14 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
        group->addChild(new SpvAsmComputeShaderCase(testCtx, "induction", "The usual way induction variables are handled in LLVM IR", spec2));
 
        spec3.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main \"main\"\n"
                "OpName %id \"gl_GlobalInvocationID\"\n"
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%f32ptr_f   = OpTypePointer Function %f32\n"
                "%id         = OpVariable %uvec3ptr Input\n"
@@ -1896,7 +1869,7 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
        }
 
        spec.assembly =
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -1904,12 +1877,12 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%u32ptr       = OpTypePointer Function %u32\n"
                "%u32ptr_input = OpTypePointer Input %u32\n"
 
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2053,7 +2026,7 @@ tcu::TestCaseGroup* createMultipleShaderGroup (tcu::TestContext& testCtx)
                "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) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%zero       = OpConstant %i32 0\n"
                "%one        = OpConstant %u32 1\n"
@@ -2163,7 +2136,7 @@ tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2246,7 +2219,7 @@ tcu::TestCaseGroup* createOpSourceExtensionGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats             (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSourceExtension \"${EXTENSION}\"\n"
 
@@ -2255,7 +2228,7 @@ tcu::TestCaseGroup* createOpSourceExtensionGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2310,7 +2283,7 @@ tcu::TestCaseGroup* createOpConstantNullGroup (tcu::TestContext& testCtx)
        vector<float>                                   positiveFloats  (numElements, 0);
        vector<float>                                   negativeFloats  (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -2318,17 +2291,9 @@ tcu::TestCaseGroup* createOpConstantNullGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
-               "%uvec2     = OpTypeVector %u32 2\n"
-               "%bvec3     = OpTypeVector %bool 3\n"
-               "%fvec4     = OpTypeVector %f32 4\n"
-               "%fmat33    = OpTypeMatrix %fvec3 3\n"
-               "%const100  = OpConstant %u32 100\n"
-               "%uarr100   = OpTypeArray %i32 %const100\n"
-               "%struct    = OpTypeStruct %f32 %i32 %u32\n"
-               "%pointer   = OpTypePointer Function %i32\n"
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
+               "${TYPE}\n"
                "%null      = OpConstantNull ${TYPE}\n"
 
                "%id        = OpVariable %uvec3ptr Input\n"
@@ -2390,7 +2355,7 @@ tcu::TestCaseGroup* createOpConstantCompositeGroup (tcu::TestContext& testCtx)
        vector<float>                                   positiveFloats  (numElements, 0);
        vector<float>                                   negativeFloats  (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -2398,7 +2363,7 @@ tcu::TestCaseGroup* createOpConstantCompositeGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2552,7 +2517,7 @@ 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) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -2560,7 +2525,7 @@ tcu::TestCaseGroup* createOpQuantizeToF16Group (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2738,22 +2703,12 @@ tcu::TestCaseGroup* createOpQuantizeToF16Group (tcu::TestContext& testCtx)
        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"));
 
        const std::string shader (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpName %main           \"main\"\n"
                "OpName %id             \"gl_GlobalInvocationID\"\n"
@@ -2767,7 +2722,7 @@ tcu::TestCaseGroup* createSpecConstantOpQuantizeToF16Group (tcu::TestContext& te
                "OpDecorate %sc_4  SpecId 4\n"
                "OpDecorate %sc_5  SpecId 5\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -2983,14 +2938,14 @@ tcu::TestCaseGroup* createOpConstantUsageGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) +
 
                "%fmat      = OpTypeMatrix %fvec3 3\n"
                "%ten       = OpConstant %u32 10\n"
                "%f32arr10  = OpTypeArray %f32 %ten\n"
                "%fst       = OpTypeStruct %f32 %f32\n"
 
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBuffer()) +
 
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
@@ -3070,7 +3025,7 @@ tcu::TestCaseGroup* createLoopControlGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats             (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -3078,7 +3033,7 @@ tcu::TestCaseGroup* createLoopControlGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%u32ptr      = OpTypePointer Function %u32\n"
 
@@ -3172,7 +3127,7 @@ tcu::TestCaseGroup* createSelectionControlGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats             (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -3180,7 +3135,7 @@ tcu::TestCaseGroup* createSelectionControlGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%id       = OpVariable %uvec3ptr Input\n"
                "%zero     = OpConstant %i32 0\n"
@@ -3266,7 +3221,7 @@ tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats             (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main \"main\"\n"
@@ -3275,7 +3230,7 @@ tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%f32f = OpTypeFunction %f32\n"
                "%id = OpVariable %uvec3ptr Input\n"
@@ -3344,7 +3299,7 @@ tcu::TestCaseGroup* createMemoryAccessGroup (tcu::TestContext& testCtx)
        vector<float>                                   inputFloats             (numElements, 0);
        vector<float>                                   outputFloats    (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -3352,7 +3307,7 @@ tcu::TestCaseGroup* createMemoryAccessGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
 
                "%f32ptr_f  = OpTypePointer Function %f32\n"
 
@@ -3415,7 +3370,7 @@ tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
        vector<float>                                   positiveFloats  (numElements, 0);
        vector<float>                                   negativeFloats  (numElements, 0);
        const StringTemplate                    shaderTemplate  (
-               string(s_ShaderPreamble) +
+               string(getComputeAsmShaderPreamble()) +
 
                "OpSource GLSL 430\n"
                "OpName %main           \"main\"\n"
@@ -3423,18 +3378,10 @@ tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
 
                "OpDecorate %id BuiltIn GlobalInvocationId\n"
 
-               + string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
-               "%uvec2     = OpTypeVector %u32 2\n"
-               "%fvec4     = OpTypeVector %f32 4\n"
-               "%fmat33    = OpTypeMatrix %fvec3 3\n"
-               "%image     = OpTypeImage %f32 2D 0 0 0 1 Unknown\n"
-               "%sampler   = OpTypeSampler\n"
-               "%simage    = OpTypeSampledImage %image\n"
-               "%const100  = OpConstant %u32 100\n"
-               "%uarr100   = OpTypeArray %i32 %const100\n"
-               "%struct    = OpTypeStruct %f32 %i32 %u32\n"
-               "%pointer   = OpTypePointer Function %i32\n"
-               + string(s_InputOutputBuffer) +
+               + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
+
+               "${TYPE}\n"
+
                "%id        = OpVariable %uvec3ptr Input\n"
                "%zero      = OpConstant %i32 0\n"
 
@@ -3490,2168 +3437,6 @@ 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
-// with an entry point named 'main_to_the_main'
-struct InstanceContext
-{
-       // Map of modules to what entry_points we care to use from those modules.
-       ModuleMap                               moduleMap;
-       RGBA                                    inputColors[4];
-       RGBA                                    outputColors[4];
-       // Concrete SPIR-V code to test via boilerplate specialization.
-       map<string, string>             testCodeFragments;
-       StageToSpecConstantMap  specConstants;
-       bool                                    hasTessellation;
-       VkShaderStageFlagBits   requiredStages;
-
-       InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_, const StageToSpecConstantMap& specConstants_)
-               : testCodeFragments             (testCodeFragments_)
-               , specConstants                 (specConstants_)
-               , hasTessellation               (false)
-               , requiredStages                (static_cast<VkShaderStageFlagBits>(0))
-       {
-               inputColors[0]          = inputs[0];
-               inputColors[1]          = inputs[1];
-               inputColors[2]          = inputs[2];
-               inputColors[3]          = inputs[3];
-
-               outputColors[0]         = outputs[0];
-               outputColors[1]         = outputs[1];
-               outputColors[2]         = outputs[2];
-               outputColors[3]         = outputs[3];
-       }
-
-       InstanceContext (const InstanceContext& other)
-               : moduleMap                     (other.moduleMap)
-               , testCodeFragments     (other.testCodeFragments)
-               , specConstants         (other.specConstants)
-               , hasTessellation       (other.hasTessellation)
-               , requiredStages    (other.requiredStages)
-       {
-               inputColors[0]          = other.inputColors[0];
-               inputColors[1]          = other.inputColors[1];
-               inputColors[2]          = other.inputColors[2];
-               inputColors[3]          = other.inputColors[3];
-
-               outputColors[0]         = other.outputColors[0];
-               outputColors[1]         = other.outputColors[1];
-               outputColors[2]         = other.outputColors[2];
-               outputColors[3]         = other.outputColors[3];
-       }
-};
-
-// A description of a shader to be used for a single stage of the graphics pipeline.
-struct ShaderElement
-{
-       // The module that contains this shader entrypoint.
-       string                                  moduleName;
-
-       // The name of the entrypoint.
-       string                                  entryName;
-
-       // Which shader stage this entry point represents.
-       VkShaderStageFlagBits   stage;
-
-       ShaderElement (const string& moduleName_, const string& entryPoint_, VkShaderStageFlagBits shaderStage_)
-               : moduleName(moduleName_)
-               , entryName(entryPoint_)
-               , stage(shaderStage_)
-       {
-       }
-};
-
-void getDefaultColors (RGBA (&colors)[4])
-{
-       colors[0] = RGBA::white();
-       colors[1] = RGBA::red();
-       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, const StageToSpecConstantMap& specConstants)
-{
-       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));
-               ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
-       }
-       return ctx;
-}
-
-template<size_t N>
-inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], 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)
-{
-       RGBA defaultColors[4];
-       getDefaultColors(defaultColors);
-       return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
-}
-
-// For the current InstanceContext, constructs the required modules and shader stage create infos.
-void createPipelineShaderStages (const DeviceInterface& vk, const VkDevice vkDevice, InstanceContext& instance, Context& context, vector<ModuleHandleSp>& modules, vector<VkPipelineShaderStageCreateInfo>& createInfos)
-{
-       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;
-                       const VkPipelineShaderStageCreateInfo   shaderParam             =
-                       {
-                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    //      VkStructureType                 sType;
-                               DE_NULL,                                                                                                //      const void*                             pNext;
-                               (VkPipelineShaderStageCreateFlags)0,
-                               stage.second,                                                                                   //      VkShaderStageFlagBits   stage;
-                               **modules.back(),                                                                               //      VkShaderModule                  module;
-                               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"                                                                                                                        \
-       "%v4bool = OpTypeVector %bool 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_f32_7 = OpConstant %f32 7.0\n"                                                                                                                      \
-       "%c_f32_8 = OpConstant %f32 8.0\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
-// on fragments, which must (at least) map "testfun" to an OpFunction definition
-// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
-// with "BP_" to avoid collisions with fragments.
-//
-// It corresponds roughly to this GLSL:
-//;
-// layout(location = 0) in vec4 position;
-// layout(location = 1) in vec4 color;
-// layout(location = 1) out highp vec4 vtxColor;
-// void main (void) { gl_Position = position; vtxColor = test_func(color); }
-string makeVertexShaderAssembly(const map<string, string>& fragments)
-{
-// \todo [2015-11-23 awoloszyn] Remove OpName once these have stabalized
-       static const char vertexShaderBoilerplate[] =
-               "OpCapability Shader\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint Vertex %main \"main\" %BP_stream %BP_position %BP_vtx_color %BP_color %BP_gl_VertexIndex %BP_gl_InstanceIndex\n"
-               "${debug:opt}\n"
-               "OpName %main \"main\"\n"
-               "OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
-               "OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
-               "OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
-               "OpName %test_code \"testfun(vf4;\"\n"
-               "OpName %BP_stream \"\"\n"
-               "OpName %BP_position \"position\"\n"
-               "OpName %BP_vtx_color \"vtxColor\"\n"
-               "OpName %BP_color \"color\"\n"
-               "OpName %BP_gl_VertexIndex \"gl_VertexIndex\"\n"
-               "OpName %BP_gl_InstanceIndex \"gl_InstanceIndex\"\n"
-               "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_gl_PerVertex Block\n"
-               "OpDecorate %BP_position Location 0\n"
-               "OpDecorate %BP_vtx_color Location 1\n"
-               "OpDecorate %BP_color Location 1\n"
-               "OpDecorate %BP_gl_VertexIndex BuiltIn VertexIndex\n"
-               "OpDecorate %BP_gl_InstanceIndex BuiltIn InstanceIndex\n"
-               "${decoration:opt}\n"
-               SPIRV_ASSEMBLY_TYPES
-               SPIRV_ASSEMBLY_CONSTANTS
-               SPIRV_ASSEMBLY_ARRAYS
-               "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_op_gl_PerVertex = OpTypePointer Output %BP_gl_PerVertex\n"
-               "%BP_stream = OpVariable %BP_op_gl_PerVertex Output\n"
-               "%BP_position = OpVariable %ip_v4f32 Input\n"
-               "%BP_vtx_color = OpVariable %op_v4f32 Output\n"
-               "%BP_color = OpVariable %ip_v4f32 Input\n"
-               "%BP_gl_VertexIndex = OpVariable %ip_i32 Input\n"
-               "%BP_gl_InstanceIndex = OpVariable %ip_i32 Input\n"
-               "${pre_main:opt}\n"
-               "%main = OpFunction %void None %fun\n"
-               "%BP_label = OpLabel\n"
-               "%BP_pos = OpLoad %v4f32 %BP_position\n"
-               "%BP_gl_pos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
-               "OpStore %BP_gl_pos %BP_pos\n"
-               "%BP_col = OpLoad %v4f32 %BP_color\n"
-               "%BP_col_transformed = OpFunctionCall %v4f32 %test_code %BP_col\n"
-               "OpStore %BP_vtx_color %BP_col_transformed\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n"
-               "${testfun}\n";
-       return tcu::StringTemplate(vertexShaderBoilerplate).specialize(fragments);
-}
-
-// Creates tess-control-shader assembly by specializing a boilerplate
-// StringTemplate on fragments, which must (at least) map "testfun" to an
-// OpFunction definition for %test_code that takes and returns a %v4f32.
-// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
-//
-// It roughly corresponds to the following GLSL.
-//
-// #version 450
-// layout(vertices = 3) out;
-// layout(location = 1) in vec4 in_color[];
-// layout(location = 1) out vec4 out_color[];
-//
-// void main() {
-//   out_color[gl_InvocationID] = testfun(in_color[gl_InvocationID]);
-//   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
-//   if (gl_InvocationID == 0) {
-//     gl_TessLevelOuter[0] = 1.0;
-//     gl_TessLevelOuter[1] = 1.0;
-//     gl_TessLevelOuter[2] = 1.0;
-//     gl_TessLevelInner[0] = 1.0;
-//   }
-// }
-string makeTessControlShaderAssembly (const map<string, string>& fragments)
-{
-       static const char tessControlShaderBoilerplate[] =
-               "OpCapability Tessellation\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint TessellationControl %BP_main \"main\" %BP_out_color %BP_gl_InvocationID %BP_in_color %BP_gl_out %BP_gl_in %BP_gl_TessLevelOuter %BP_gl_TessLevelInner\n"
-               "OpExecutionMode %BP_main OutputVertices 3\n"
-               "${debug:opt}\n"
-               "OpName %BP_main \"main\"\n"
-               "OpName %test_code \"testfun(vf4;\"\n"
-               "OpName %BP_out_color \"out_color\"\n"
-               "OpName %BP_gl_InvocationID \"gl_InvocationID\"\n"
-               "OpName %BP_in_color \"in_color\"\n"
-               "OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
-               "OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
-               "OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
-               "OpName %BP_gl_out \"gl_out\"\n"
-               "OpName %BP_gl_PVOut \"gl_PerVertex\"\n"
-               "OpMemberName %BP_gl_PVOut 0 \"gl_Position\"\n"
-               "OpMemberName %BP_gl_PVOut 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_gl_PVOut 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_gl_PVOut 3 \"gl_CullDistance\"\n"
-               "OpName %BP_gl_in \"gl_in\"\n"
-               "OpName %BP_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
-               "OpName %BP_gl_TessLevelInner \"gl_TessLevelInner\"\n"
-               "OpDecorate %BP_out_color Location 1\n"
-               "OpDecorate %BP_gl_InvocationID BuiltIn InvocationId\n"
-               "OpDecorate %BP_in_color Location 1\n"
-               "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_gl_PerVertex Block\n"
-               "OpMemberDecorate %BP_gl_PVOut 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_gl_PVOut 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_gl_PVOut 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_gl_PVOut 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_gl_PVOut Block\n"
-               "OpDecorate %BP_gl_TessLevelOuter Patch\n"
-               "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
-               "%BP_out_color = OpVariable %op_a3v4f32 Output\n"
-               "%BP_gl_InvocationID = OpVariable %ip_i32 Input\n"
-               "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
-               "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_a3_gl_PerVertex = OpTypeArray %BP_gl_PerVertex %c_u32_3\n"
-               "%BP_op_a3_gl_PerVertex = OpTypePointer Output %BP_a3_gl_PerVertex\n"
-               "%BP_gl_out = OpVariable %BP_op_a3_gl_PerVertex Output\n"
-               "%BP_gl_PVOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_a32_gl_PVOut = OpTypeArray %BP_gl_PVOut %c_u32_32\n"
-               "%BP_ip_a32_gl_PVOut = OpTypePointer Input %BP_a32_gl_PVOut\n"
-               "%BP_gl_in = OpVariable %BP_ip_a32_gl_PVOut 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"
-
-               "%BP_gl_Invoc = OpLoad %i32 %BP_gl_InvocationID\n"
-
-               "%BP_in_col_loc = OpAccessChain %ip_v4f32 %BP_in_color %BP_gl_Invoc\n"
-               "%BP_out_col_loc = OpAccessChain %op_v4f32 %BP_out_color %BP_gl_Invoc\n"
-               "%BP_in_col_val = OpLoad %v4f32 %BP_in_col_loc\n"
-               "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_in_col_val\n"
-               "OpStore %BP_out_col_loc %BP_clr_transformed\n"
-
-               "%BP_in_pos_loc = OpAccessChain %ip_v4f32 %BP_gl_in %BP_gl_Invoc %c_i32_0\n"
-               "%BP_out_pos_loc = OpAccessChain %op_v4f32 %BP_gl_out %BP_gl_Invoc %c_i32_0\n"
-               "%BP_in_pos_val = OpLoad %v4f32 %BP_in_pos_loc\n"
-               "OpStore %BP_out_pos_loc %BP_in_pos_val\n"
-
-               "%BP_cmp = OpIEqual %bool %BP_gl_Invoc %c_i32_0\n"
-               "OpSelectionMerge %BP_merge_label None\n"
-               "OpBranchConditional %BP_cmp %BP_if_label %BP_merge_label\n"
-               "%BP_if_label = OpLabel\n"
-               "%BP_gl_TessLevelOuterPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_0\n"
-               "%BP_gl_TessLevelOuterPos_1 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_1\n"
-               "%BP_gl_TessLevelOuterPos_2 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_2\n"
-               "%BP_gl_TessLevelInnerPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelInner %c_i32_0\n"
-               "OpStore %BP_gl_TessLevelOuterPos_0 %c_f32_1\n"
-               "OpStore %BP_gl_TessLevelOuterPos_1 %c_f32_1\n"
-               "OpStore %BP_gl_TessLevelOuterPos_2 %c_f32_1\n"
-               "OpStore %BP_gl_TessLevelInnerPos_0 %c_f32_1\n"
-               "OpBranch %BP_merge_label\n"
-               "%BP_merge_label = OpLabel\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n"
-               "${testfun}\n";
-       return tcu::StringTemplate(tessControlShaderBoilerplate).specialize(fragments);
-}
-
-// Creates tess-evaluation-shader assembly by specializing a boilerplate
-// StringTemplate on fragments, which must (at least) map "testfun" to an
-// OpFunction definition for %test_code that takes and returns a %v4f32.
-// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
-//
-// It roughly corresponds to the following glsl.
-//
-// #version 450
-//
-// layout(triangles, equal_spacing, ccw) in;
-// layout(location = 1) in vec4 in_color[];
-// layout(location = 1) out vec4 out_color;
-//
-// #define interpolate(val)
-//   vec4(gl_TessCoord.x) * val[0] + vec4(gl_TessCoord.y) * val[1] +
-//          vec4(gl_TessCoord.z) * val[2]
-//
-// void main() {
-//   gl_Position = vec4(gl_TessCoord.x) * gl_in[0].gl_Position +
-//                  vec4(gl_TessCoord.y) * gl_in[1].gl_Position +
-//                  vec4(gl_TessCoord.z) * gl_in[2].gl_Position;
-//   out_color = testfun(interpolate(in_color));
-// }
-string makeTessEvalShaderAssembly(const map<string, string>& fragments)
-{
-       static const char tessEvalBoilerplate[] =
-               "OpCapability Tessellation\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint TessellationEvaluation %BP_main \"main\" %BP_stream %BP_gl_TessCoord %BP_gl_in %BP_out_color %BP_in_color\n"
-               "OpExecutionMode %BP_main Triangles\n"
-               "OpExecutionMode %BP_main SpacingEqual\n"
-               "OpExecutionMode %BP_main VertexOrderCcw\n"
-               "${debug:opt}\n"
-               "OpName %BP_main \"main\"\n"
-               "OpName %test_code \"testfun(vf4;\"\n"
-               "OpName %BP_gl_PerVertexOut \"gl_PerVertex\"\n"
-               "OpMemberName %BP_gl_PerVertexOut 0 \"gl_Position\"\n"
-               "OpMemberName %BP_gl_PerVertexOut 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_gl_PerVertexOut 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_gl_PerVertexOut 3 \"gl_CullDistance\"\n"
-               "OpName %BP_stream \"\"\n"
-               "OpName %BP_gl_TessCoord \"gl_TessCoord\"\n"
-               "OpName %BP_gl_PerVertexIn \"gl_PerVertex\"\n"
-               "OpMemberName %BP_gl_PerVertexIn 0 \"gl_Position\"\n"
-               "OpMemberName %BP_gl_PerVertexIn 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_gl_PerVertexIn 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_gl_PerVertexIn 3 \"gl_CullDistance\"\n"
-               "OpName %BP_gl_in \"gl_in\"\n"
-               "OpName %BP_out_color \"out_color\"\n"
-               "OpName %BP_in_color \"in_color\"\n"
-               "OpMemberDecorate %BP_gl_PerVertexOut 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_gl_PerVertexOut 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_gl_PerVertexOut 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_gl_PerVertexOut 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_gl_PerVertexOut Block\n"
-               "OpDecorate %BP_gl_TessCoord BuiltIn TessCoord\n"
-               "OpMemberDecorate %BP_gl_PerVertexIn 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_gl_PerVertexIn 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_gl_PerVertexIn 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_gl_PerVertexIn 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_gl_PerVertexIn Block\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
-               "%BP_gl_PerVertexOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_op_gl_PerVertexOut = OpTypePointer Output %BP_gl_PerVertexOut\n"
-               "%BP_stream = OpVariable %BP_op_gl_PerVertexOut Output\n"
-               "%BP_gl_TessCoord = OpVariable %ip_v3f32 Input\n"
-               "%BP_gl_PerVertexIn = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_a32_gl_PerVertexIn = OpTypeArray %BP_gl_PerVertexIn %c_u32_32\n"
-               "%BP_ip_a32_gl_PerVertexIn = OpTypePointer Input %BP_a32_gl_PerVertexIn\n"
-               "%BP_gl_in = OpVariable %BP_ip_a32_gl_PerVertexIn 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_gl_TC_0 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_0\n"
-               "%BP_gl_TC_1 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_1\n"
-               "%BP_gl_TC_2 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_2\n"
-               "%BP_gl_in_gl_Pos_0 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
-               "%BP_gl_in_gl_Pos_1 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
-               "%BP_gl_in_gl_Pos_2 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
-
-               "%BP_gl_OPos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
-               "%BP_in_color_0 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
-               "%BP_in_color_1 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
-               "%BP_in_color_2 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
-
-               "%BP_TC_W_0 = OpLoad %f32 %BP_gl_TC_0\n"
-               "%BP_TC_W_1 = OpLoad %f32 %BP_gl_TC_1\n"
-               "%BP_TC_W_2 = OpLoad %f32 %BP_gl_TC_2\n"
-               "%BP_v4f32_TC_0 = OpCompositeConstruct %v4f32 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0\n"
-               "%BP_v4f32_TC_1 = OpCompositeConstruct %v4f32 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1\n"
-               "%BP_v4f32_TC_2 = OpCompositeConstruct %v4f32 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2\n"
-
-               "%BP_gl_IP_0 = OpLoad %v4f32 %BP_gl_in_gl_Pos_0\n"
-               "%BP_gl_IP_1 = OpLoad %v4f32 %BP_gl_in_gl_Pos_1\n"
-               "%BP_gl_IP_2 = OpLoad %v4f32 %BP_gl_in_gl_Pos_2\n"
-
-               "%BP_IP_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_gl_IP_0\n"
-               "%BP_IP_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_gl_IP_1\n"
-               "%BP_IP_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_gl_IP_2\n"
-
-               "%BP_pos_sum_0 = OpFAdd %v4f32 %BP_IP_W_0 %BP_IP_W_1\n"
-               "%BP_pos_sum_1 = OpFAdd %v4f32 %BP_pos_sum_0 %BP_IP_W_2\n"
-
-               "OpStore %BP_gl_OPos %BP_pos_sum_1\n"
-
-               "%BP_IC_0 = OpLoad %v4f32 %BP_in_color_0\n"
-               "%BP_IC_1 = OpLoad %v4f32 %BP_in_color_1\n"
-               "%BP_IC_2 = OpLoad %v4f32 %BP_in_color_2\n"
-
-               "%BP_IC_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_IC_0\n"
-               "%BP_IC_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_IC_1\n"
-               "%BP_IC_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_IC_2\n"
-
-               "%BP_col_sum_0 = OpFAdd %v4f32 %BP_IC_W_0 %BP_IC_W_1\n"
-               "%BP_col_sum_1 = OpFAdd %v4f32 %BP_col_sum_0 %BP_IC_W_2\n"
-
-               "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_col_sum_1\n"
-
-               "OpStore %BP_out_color %BP_clr_transformed\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n"
-               "${testfun}\n";
-       return tcu::StringTemplate(tessEvalBoilerplate).specialize(fragments);
-}
-
-// Creates geometry-shader assembly by specializing a boilerplate StringTemplate
-// on fragments, which must (at least) map "testfun" to an OpFunction definition
-// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
-// with "BP_" to avoid collisions with fragments.
-//
-// Derived from this GLSL:
-//
-// #version 450
-// layout(triangles) in;
-// layout(triangle_strip, max_vertices = 3) out;
-//
-// layout(location = 1) in vec4 in_color[];
-// layout(location = 1) out vec4 out_color;
-//
-// void main() {
-//   gl_Position = gl_in[0].gl_Position;
-//   out_color = test_fun(in_color[0]);
-//   EmitVertex();
-//   gl_Position = gl_in[1].gl_Position;
-//   out_color = test_fun(in_color[1]);
-//   EmitVertex();
-//   gl_Position = gl_in[2].gl_Position;
-//   out_color = test_fun(in_color[2]);
-//   EmitVertex();
-//   EndPrimitive();
-// }
-string makeGeometryShaderAssembly(const map<string, string>& fragments)
-{
-       static const char geometryShaderBoilerplate[] =
-               "OpCapability Geometry\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint Geometry %BP_main \"main\" %BP_out_gl_position %BP_gl_in %BP_out_color %BP_in_color\n"
-               "OpExecutionMode %BP_main Triangles\n"
-               "OpExecutionMode %BP_main OutputTriangleStrip\n"
-               "OpExecutionMode %BP_main OutputVertices 3\n"
-               "${debug:opt}\n"
-               "OpName %BP_main \"main\"\n"
-               "OpName %BP_per_vertex_in \"gl_PerVertex\"\n"
-               "OpMemberName %BP_per_vertex_in 0 \"gl_Position\"\n"
-               "OpMemberName %BP_per_vertex_in 1 \"gl_PointSize\"\n"
-               "OpMemberName %BP_per_vertex_in 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %BP_per_vertex_in 3 \"gl_CullDistance\"\n"
-               "OpName %BP_gl_in \"gl_in\"\n"
-               "OpName %BP_out_color \"out_color\"\n"
-               "OpName %BP_in_color \"in_color\"\n"
-               "OpName %test_code \"testfun(vf4;\"\n"
-               "OpDecorate %BP_out_gl_position BuiltIn Position\n"
-               "OpMemberDecorate %BP_per_vertex_in 0 BuiltIn Position\n"
-               "OpMemberDecorate %BP_per_vertex_in 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %BP_per_vertex_in 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %BP_per_vertex_in 3 BuiltIn CullDistance\n"
-               "OpDecorate %BP_per_vertex_in Block\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
-               "%BP_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
-               "%BP_a3_per_vertex_in = OpTypeArray %BP_per_vertex_in %c_u32_3\n"
-               "%BP_ip_a3_per_vertex_in = OpTypePointer Input %BP_a3_per_vertex_in\n"
-
-               "%BP_gl_in = OpVariable %BP_ip_a3_per_vertex_in Input\n"
-               "%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"
-               "%BP_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
-               "%BP_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
-               "%BP_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
-
-               "%BP_in_position_0 = OpLoad %v4f32 %BP_gl_in_0_gl_position\n"
-               "%BP_in_position_1 = OpLoad %v4f32 %BP_gl_in_1_gl_position\n"
-               "%BP_in_position_2 = OpLoad %v4f32 %BP_gl_in_2_gl_position \n"
-
-               "%BP_in_color_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
-               "%BP_in_color_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
-               "%BP_in_color_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
-
-               "%BP_in_color_0 = OpLoad %v4f32 %BP_in_color_0_ptr\n"
-               "%BP_in_color_1 = OpLoad %v4f32 %BP_in_color_1_ptr\n"
-               "%BP_in_color_2 = OpLoad %v4f32 %BP_in_color_2_ptr\n"
-
-               "%BP_transformed_in_color_0 = OpFunctionCall %v4f32 %test_code %BP_in_color_0\n"
-               "%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"
-
-               "OpStore %BP_out_gl_position %BP_in_position_1\n"
-               "OpStore %BP_out_color %BP_transformed_in_color_1\n"
-               "OpEmitVertex\n"
-
-               "OpStore %BP_out_gl_position %BP_in_position_2\n"
-               "OpStore %BP_out_color %BP_transformed_in_color_2\n"
-               "OpEmitVertex\n"
-
-               "OpEndPrimitive\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n"
-               "${testfun}\n";
-       return tcu::StringTemplate(geometryShaderBoilerplate).specialize(fragments);
-}
-
-// Creates fragment-shader assembly by specializing a boilerplate StringTemplate
-// on fragments, which must (at least) map "testfun" to an OpFunction definition
-// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
-// with "BP_" to avoid collisions with fragments.
-//
-// Derived from this GLSL:
-//
-// layout(location = 1) in highp vec4 vtxColor;
-// layout(location = 0) out highp vec4 fragColor;
-// highp vec4 testfun(highp vec4 x) { return x; }
-// void main(void) { fragColor = testfun(vtxColor); }
-//
-// with modifications including passing vtxColor by value and ripping out
-// testfun() definition.
-string makeFragmentShaderAssembly(const map<string, string>& fragments)
-{
-       static const char fragmentShaderBoilerplate[] =
-               "OpCapability Shader\n"
-               "OpMemoryModel Logical GLSL450\n"
-               "OpEntryPoint Fragment %BP_main \"main\" %BP_vtxColor %BP_fragColor\n"
-               "OpExecutionMode %BP_main OriginUpperLeft\n"
-               "${debug:opt}\n"
-               "OpName %BP_main \"main\"\n"
-               "OpName %BP_fragColor \"fragColor\"\n"
-               "OpName %BP_vtxColor \"vtxColor\"\n"
-               "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"
-               "%BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1\n"
-               "OpStore %BP_fragColor %BP_tmp2\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n"
-               "${testfun}\n";
-       return tcu::StringTemplate(fragmentShaderBoilerplate).specialize(fragments);
-}
-
-// Creates fragments that specialize into a simple pass-through shader (of any kind).
-map<string, string> passthruFragments(void)
-{
-       map<string, string> fragments;
-       fragments["testfun"] =
-               // A %test_code function that returns its argument unchanged.
-               "%test_code = OpFunction %v4f32 None %v4f32_function\n"
-               "%param1 = OpFunctionParameter %v4f32\n"
-               "%label_testfun = OpLabel\n"
-               "OpReturnValue %param1\n"
-               "OpFunctionEnd\n";
-       return fragments;
-}
-
-// 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)
-{
-       map<string, string> passthru = passthruFragments();
-       dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
-       dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
-}
-
-// 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)
-{
-       map<string, string> passthru = passthruFragments();
-       dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
-       dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
-       dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
-       dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
-}
-
-// 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)
-{
-       map<string, string> passthru = passthruFragments();
-       dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
-       dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
-       dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(context.testCodeFragments);
-       dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
-}
-
-// 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)
-{
-       map<string, string> passthru = passthruFragments();
-       dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
-       dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(context.testCodeFragments);
-       dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
-}
-
-// 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)
-{
-       map<string, string> passthru = passthruFragments();
-       dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
-       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 OpMemberName at some point
-       dst.spirvAsmSources.add("module") <<
-               "OpCapability Shader\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\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\" %geom_out_gl_position %geom_gl_in %geom_out_color %geom_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 OutputTriangleStrip\n"
-               "OpExecutionMode %geom_main OutputVertices 3\n"
-
-               "OpExecutionMode %tessc_main OutputVertices 3\n"
-
-               "OpExecutionMode %tesse_main Triangles\n"
-               "OpExecutionMode %tesse_main SpacingEqual\n"
-               "OpExecutionMode %tesse_main VertexOrderCcw\n"
-
-               "OpExecutionMode %frag_main OriginUpperLeft\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_VertexIndex\"\n"
-               "OpName %vert_instance_id \"gl_InstanceIndex\"\n"
-               "OpName %geom_main \"main\"\n"
-               "OpName %geom_per_vertex_in \"gl_PerVertex\"\n"
-               "OpMemberName %geom_per_vertex_in 0 \"gl_Position\"\n"
-               "OpMemberName %geom_per_vertex_in 1 \"gl_PointSize\"\n"
-               "OpMemberName %geom_per_vertex_in 2 \"gl_ClipDistance\"\n"
-               "OpMemberName %geom_per_vertex_in 3 \"gl_CullDistance\"\n"
-               "OpName %geom_gl_in \"gl_in\"\n"
-               "OpName %geom_out_color \"out_color\"\n"
-               "OpName %geom_in_color \"in_color\"\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"
-               "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"
-               "OpName %frag_main \"main\"\n"
-               "OpName %frag_fragColor \"fragColor\"\n"
-               "OpName %frag_vtxColor \"vtxColor\"\n"
-
-               "; Vertex decorations\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 VertexIndex\n"
-               "OpDecorate %vert_instance_id BuiltIn InstanceIndex\n"
-
-               "; Geometry decorations\n"
-               "OpDecorate %geom_out_gl_position BuiltIn Position\n"
-               "OpMemberDecorate %geom_per_vertex_in 0 BuiltIn Position\n"
-               "OpMemberDecorate %geom_per_vertex_in 1 BuiltIn PointSize\n"
-               "OpMemberDecorate %geom_per_vertex_in 2 BuiltIn ClipDistance\n"
-               "OpMemberDecorate %geom_per_vertex_in 3 BuiltIn CullDistance\n"
-               "OpDecorate %geom_per_vertex_in Block\n"
-               "OpDecorate %geom_out_color Location 1\n"
-               "OpDecorate %geom_in_color Location 1\n"
-
-               "; Tessellation Control decorations\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"
-               "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"
-               "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 %geom_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 %tesse_in_pos_0 %tesse_tc_0\n"
-               "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_1 %tesse_tc_1\n"
-               "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_2 %tesse_tc_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_in_clr_0 %tesse_tc_0\n"
-               "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_1 %tesse_tc_1\n"
-               "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_2 %tesse_tc_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 \"vert1\"\n"
-               "OpName %main2 \"vert2\"\n"
-               "OpName %vtxPosition \"vtxPosition\"\n"
-               "OpName %Position \"position\"\n"
-               "OpName %vtxColor \"vtxColor\"\n"
-               "OpName %color \"color\"\n"
-               "OpName %vertex_id \"gl_VertexIndex\"\n"
-               "OpName %instance_id \"gl_InstanceIndex\"\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 VertexIndex\n"
-               "OpDecorate %instance_id BuiltIn InstanceIndex\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"
-               "%tmp_color4 = OpVectorInsertDynamic %v4f32 %tmp_color3 %c_f32_1 %c_i32_3\n"
-               "OpStore %vtxColor %tmp_color4\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"
-               "%tmp4 = OpVectorInsertDynamic %v4f32 %tmp3 %c_f32_1 %c_i32_3\n"
-               "OpStore %fragColor %tmp4\n"
-               "OpReturn\n"
-               "OpFunctionEnd\n";
-
-       dst.spirvAsmSources.add("geom") <<
-               "OpCapability Geometry\n"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\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 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 %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"
-               "%geom2_transformed_in_color_0_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_0 %c_f32_1 %c_i32_3\n"
-               "%geom2_transformed_in_color_1_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_1 %c_f32_1 %c_i32_3\n"
-               "%geom2_transformed_in_color_2_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_2 %c_f32_1 %c_i32_3\n"
-               "OpStore %out_gl_position %geom2_in_position_0\n"
-               "OpStore %out_color %geom2_transformed_in_color_0_a\n"
-               "OpEmitVertex\n"
-               "OpStore %out_gl_position %geom2_in_position_1\n"
-               "OpStore %out_color %geom2_transformed_in_color_1_a\n"
-               "OpEmitVertex\n"
-               "OpStore %out_gl_position %geom2_in_position_2\n"
-               "OpStore %out_color %geom2_transformed_in_color_2_a\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 %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"
-               "%tessc2_transformed_color_a = OpVectorInsertDynamic %v4f32 %tessc2_transformed_color %c_f32_1 %c_i32_3\n"
-               "OpStore %tessc2_out_color_ptr %tessc2_transformed_color_a\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 %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"
-               "OpCapability ClipDistance\n"
-               "OpCapability CullDistance\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 %tesse1_main SpacingEqual\n"
-               "OpExecutionMode %tesse1_main VertexOrderCcw\n"
-               "OpExecutionMode %tesse2_main Triangles\n"
-               "OpExecutionMode %tesse2_main SpacingEqual\n"
-               "OpExecutionMode %tesse2_main VertexOrderCcw\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_in_pos_0 %tesse1_tc_0\n"
-               "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
-               "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_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_in_clr_0 %tesse1_tc_0\n"
-               "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
-               "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_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_in_pos_0 %tesse2_tc_0\n"
-               "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_1 %tesse2_tc_1\n"
-               "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_2 %tesse2_tc_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_in_clr_0 %tesse2_tc_0\n"
-               "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_1 %tesse2_tc_1\n"
-               "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_2 %tesse2_tc_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"
-               "%tesse2_clr_transformed_a = OpVectorInsertDynamic %v4f32 %tesse2_clr_transformed %c_f32_1 %c_i32_3\n"
-               "OpStore %out_color %tesse2_clr_transformed_a\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
-// whatever the shaders draw can be directly spot-checked.
-TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance)
-{
-       const VkDevice                                                          vkDevice                                = context.getDevice();
-       const DeviceInterface&                                          vk                                              = context.getDeviceInterface();
-       const VkQueue                                                           queue                                   = context.getUniversalQueue();
-       const deUint32                                                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
-       const tcu::UVec2                                                        renderSize                              (256, 256);
-       vector<ModuleHandleSp>                                          modules;
-       map<VkShaderStageFlagBits, VkShaderModule>      moduleByStage;
-       const int                                                                       testSpecificSeed                = 31354125;
-       const int                                                                       seed                                    = context.getTestContext().getCommandLine().getBaseSeed() ^ testSpecificSeed;
-       bool                                                                            supportsGeometry                = false;
-       bool                                                                            supportsTessellation    = false;
-       bool                                                                            hasTessellation         = false;
-
-       const VkPhysicalDeviceFeatures&                         features                                = context.getDeviceFeatures();
-       supportsGeometry                = features.geometryShader == VK_TRUE;
-       supportsTessellation    = features.tessellationShader == VK_TRUE;
-       hasTessellation                 = (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) ||
-                                                               (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
-
-       if (hasTessellation && !supportsTessellation)
-       {
-               throw tcu::NotSupportedError(std::string("Tessellation not supported"));
-       }
-
-       if ((instance.requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) &&
-               !supportsGeometry)
-       {
-               throw tcu::NotSupportedError(std::string("Geometry not supported"));
-       }
-
-       de::Random(seed).shuffle(instance.inputColors, instance.inputColors+4);
-       de::Random(seed).shuffle(instance.outputColors, instance.outputColors+4);
-       const Vec4                                                              vertexData[]                    =
-       {
-               // Upper left corner:
-               Vec4(-1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
-               Vec4(-0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
-               Vec4(-1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
-
-               // Upper right corner:
-               Vec4(+0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
-               Vec4(+1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
-               Vec4(+1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
-
-               // Lower left corner:
-               Vec4(-1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
-               Vec4(-0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
-               Vec4(-1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
-
-               // Lower right corner:
-               Vec4(+1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
-               Vec4(+1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
-               Vec4(+0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec()
-       };
-       const size_t                                                    singleVertexDataSize    = 2 * sizeof(Vec4);
-       const size_t                                                    vertexCount                             = sizeof(vertexData) / singleVertexDataSize;
-
-       const VkBufferCreateInfo                                vertexBufferParams              =
-       {
-               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   //      VkStructureType         sType;
-               DE_NULL,                                                                //      const void*                     pNext;
-               0u,                                                                             //      VkBufferCreateFlags     flags;
-               (VkDeviceSize)sizeof(vertexData),               //      VkDeviceSize            size;
-               VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,              //      VkBufferUsageFlags      usage;
-               VK_SHARING_MODE_EXCLUSIVE,                              //      VkSharingMode           sharingMode;
-               1u,                                                                             //      deUint32                        queueFamilyCount;
-               &queueFamilyIndex,                                              //      const deUint32*         pQueueFamilyIndices;
-       };
-       const Unique<VkBuffer>                                  vertexBuffer                    (createBuffer(vk, vkDevice, &vertexBufferParams));
-       const UniquePtr<Allocation>                             vertexBufferMemory              (context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible));
-
-       VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
-
-       const VkDeviceSize                                              imageSizeBytes                  = (VkDeviceSize)(sizeof(deUint32)*renderSize.x()*renderSize.y());
-       const VkBufferCreateInfo                                readImageBufferParams   =
-       {
-               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //      VkStructureType         sType;
-               DE_NULL,                                                                        //      const void*                     pNext;
-               0u,                                                                                     //      VkBufferCreateFlags     flags;
-               imageSizeBytes,                                                         //      VkDeviceSize            size;
-               VK_BUFFER_USAGE_TRANSFER_DST_BIT,                       //      VkBufferUsageFlags      usage;
-               VK_SHARING_MODE_EXCLUSIVE,                                      //      VkSharingMode           sharingMode;
-               1u,                                                                                     //      deUint32                        queueFamilyCount;
-               &queueFamilyIndex,                                                      //      const deUint32*         pQueueFamilyIndices;
-       };
-       const Unique<VkBuffer>                                  readImageBuffer                 (createBuffer(vk, vkDevice, &readImageBufferParams));
-       const UniquePtr<Allocation>                             readImageBufferMemory   (context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
-
-       VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
-
-       const VkImageCreateInfo                                 imageParams                             =
-       {
-               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                    //      VkStructureType         sType;
-               DE_NULL,                                                                                                                                //      const void*                     pNext;
-               0u,                                                                                                                                             //      VkImageCreateFlags      flags;
-               VK_IMAGE_TYPE_2D,                                                                                                               //      VkImageType                     imageType;
-               VK_FORMAT_R8G8B8A8_UNORM,                                                                                               //      VkFormat                        format;
-               { renderSize.x(), renderSize.y(), 1 },                                                                  //      VkExtent3D                      extent;
-               1u,                                                                                                                                             //      deUint32                        mipLevels;
-               1u,                                                                                                                                             //      deUint32                        arraySize;
-               VK_SAMPLE_COUNT_1_BIT,                                                                                                  //      deUint32                        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                        queueFamilyCount;
-               &queueFamilyIndex,                                                                                                              //      const deUint32*         pQueueFamilyIndices;
-               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                              //      VkImageLayout           initialLayout;
-       };
-
-       const Unique<VkImage>                                   image                                   (createImage(vk, vkDevice, &imageParams));
-       const UniquePtr<Allocation>                             imageMemory                             (context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any));
-
-       VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageMemory->getMemory(), imageMemory->getOffset()));
-
-       const VkAttachmentDescription                   colorAttDesc                    =
-       {
-               0u,                                                                                             //      VkAttachmentDescriptionFlags    flags;
-               VK_FORMAT_R8G8B8A8_UNORM,                                               //      VkFormat                                                format;
-               VK_SAMPLE_COUNT_1_BIT,                                                  //      deUint32                                                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                             colorAttRef                             =
-       {
-               0u,                                                                                             //      deUint32                attachment;
-               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               //      VkImageLayout   layout;
-       };
-       const VkSubpassDescription                              subpassDesc                             =
-       {
-               0u,                                                                                             //      VkSubpassDescriptionFlags               flags;
-               VK_PIPELINE_BIND_POINT_GRAPHICS,                                //      VkPipelineBindPoint                             pipelineBindPoint;
-               0u,                                                                                             //      deUint32                                                inputCount;
-               DE_NULL,                                                                                //      const VkAttachmentReference*    pInputAttachments;
-               1u,                                                                                             //      deUint32                                                colorCount;
-               &colorAttRef,                                                                   //      const VkAttachmentReference*    pColorAttachments;
-               DE_NULL,                                                                                //      const VkAttachmentReference*    pResolveAttachments;
-               DE_NULL,                                                                                //      const VkAttachmentReference*    pDepthStencilAttachment;
-               0u,                                                                                             //      deUint32                                                preserveCount;
-               DE_NULL,                                                                                //      const VkAttachmentReference*    pPreserveAttachments;
-
-       };
-       const VkRenderPassCreateInfo                    renderPassParams                =
-       {
-               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,              //      VkStructureType                                 sType;
-               DE_NULL,                                                                                //      const void*                                             pNext;
-               (VkRenderPassCreateFlags)0,
-               1u,                                                                                             //      deUint32                                                attachmentCount;
-               &colorAttDesc,                                                                  //      const VkAttachmentDescription*  pAttachments;
-               1u,                                                                                             //      deUint32                                                subpassCount;
-               &subpassDesc,                                                                   //      const VkSubpassDescription*             pSubpasses;
-               0u,                                                                                             //      deUint32                                                dependencyCount;
-               DE_NULL,                                                                                //      const VkSubpassDependency*              pDependencies;
-       };
-       const Unique<VkRenderPass>                              renderPass                              (createRenderPass(vk, vkDevice, &renderPassParams));
-
-       const VkImageViewCreateInfo                             colorAttViewParams              =
-       {
-               VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,               //      VkStructureType                         sType;
-               DE_NULL,                                                                                //      const void*                                     pNext;
-               0u,                                                                                             //      VkImageViewCreateFlags          flags;
-               *image,                                                                                 //      VkImage                                         image;
-               VK_IMAGE_VIEW_TYPE_2D,                                                  //      VkImageViewType                         viewType;
-               VK_FORMAT_R8G8B8A8_UNORM,                                               //      VkFormat                                        format;
-               {
-                       VK_COMPONENT_SWIZZLE_R,
-                       VK_COMPONENT_SWIZZLE_G,
-                       VK_COMPONENT_SWIZZLE_B,
-                       VK_COMPONENT_SWIZZLE_A
-               },                                                                                              //      VkChannelMapping                        channels;
-               {
-                       VK_IMAGE_ASPECT_COLOR_BIT,                                              //      VkImageAspectFlags      aspectMask;
-                       0u,                                                                                             //      deUint32                        baseMipLevel;
-                       1u,                                                                                             //      deUint32                        mipLevels;
-                       0u,                                                                                             //      deUint32                        baseArrayLayer;
-                       1u,                                                                                             //      deUint32                        arraySize;
-               },                                                                                              //      VkImageSubresourceRange         subresourceRange;
-       };
-       const Unique<VkImageView>                               colorAttView                    (createImageView(vk, vkDevice, &colorAttViewParams));
-
-
-       // Pipeline layout
-       const VkPipelineLayoutCreateInfo                pipelineLayoutParams    =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,                  //      VkStructureType                                 sType;
-               DE_NULL,                                                                                                //      const void*                                             pNext;
-               (VkPipelineLayoutCreateFlags)0,
-               0u,                                                                                                             //      deUint32                                                descriptorSetCount;
-               DE_NULL,                                                                                                //      const VkDescriptorSetLayout*    pSetLayouts;
-               0u,                                                                                                             //      deUint32                                                pushConstantRangeCount;
-               DE_NULL,                                                                                                //      const VkPushConstantRange*              pPushConstantRanges;
-       };
-       const Unique<VkPipelineLayout>                  pipelineLayout                  (createPipelineLayout(vk, vkDevice, &pipelineLayoutParams));
-
-       // Pipeline
-       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.resize(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;
-               DE_NULL,                                                                                                        //      const void*                     pNext;
-               (VkPipelineDepthStencilStateCreateFlags)0,
-               DE_FALSE,                                                                                                       //      deUint32                        depthTestEnable;
-               DE_FALSE,                                                                                                       //      deUint32                        depthWriteEnable;
-               VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp                     depthCompareOp;
-               DE_FALSE,                                                                                                       //      deUint32                        depthBoundsTestEnable;
-               DE_FALSE,                                                                                                       //      deUint32                        stencilTestEnable;
-               {
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilFailOp;
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilPassOp;
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilDepthFailOp;
-                       VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp     stencilCompareOp;
-                       0u,                                                                                                                     //      deUint32        stencilCompareMask;
-                       0u,                                                                                                                     //      deUint32        stencilWriteMask;
-                       0u,                                                                                                                     //      deUint32        stencilReference;
-               },                                                                                                                      //      VkStencilOpState        front;
-               {
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilFailOp;
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilPassOp;
-                       VK_STENCIL_OP_KEEP,                                                                                     //      VkStencilOp     stencilDepthFailOp;
-                       VK_COMPARE_OP_ALWAYS,                                                                           //      VkCompareOp     stencilCompareOp;
-                       0u,                                                                                                                     //      deUint32        stencilCompareMask;
-                       0u,                                                                                                                     //      deUint32        stencilWriteMask;
-                       0u,                                                                                                                     //      deUint32        stencilReference;
-               },                                                                                                                      //      VkStencilOpState        back;
-               -1.0f,                                                                                                          //      float                           minDepthBounds;
-               +1.0f,                                                                                                          //      float                           maxDepthBounds;
-       };
-       const VkViewport                                                viewport0                               =
-       {
-               0.0f,                                                                                                           //      float   originX;
-               0.0f,                                                                                                           //      float   originY;
-               (float)renderSize.x(),                                                                          //      float   width;
-               (float)renderSize.y(),                                                                          //      float   height;
-               0.0f,                                                                                                           //      float   minDepth;
-               1.0f,                                                                                                           //      float   maxDepth;
-       };
-       const VkRect2D                                                  scissor0                                =
-       {
-               {
-                       0u,                                                                                                                     //      deInt32 x;
-                       0u,                                                                                                                     //      deInt32 y;
-               },                                                                                                                      //      VkOffset2D      offset;
-               {
-                       renderSize.x(),                                                                                         //      deInt32 width;
-                       renderSize.y(),                                                                                         //      deInt32 height;
-               },                                                                                                                      //      VkExtent2D      extent;
-       };
-       const VkPipelineViewportStateCreateInfo         viewportParams                  =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,          //      VkStructureType         sType;
-               DE_NULL,                                                                                                        //      const void*                     pNext;
-               (VkPipelineViewportStateCreateFlags)0,
-               1u,                                                                                                                     //      deUint32                        viewportCount;
-               &viewport0,
-               1u,
-               &scissor0
-       };
-       const VkSampleMask                                                      sampleMask                              = ~0u;
-       const VkPipelineMultisampleStateCreateInfo      multisampleParams               =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       //      VkStructureType                 sType;
-               DE_NULL,                                                                                                        //      const void*                             pNext;
-               (VkPipelineMultisampleStateCreateFlags)0,
-               VK_SAMPLE_COUNT_1_BIT,                                                                          //      VkSampleCountFlagBits   rasterSamples;
-               DE_FALSE,                                                                                                       //      deUint32                                sampleShadingEnable;
-               0.0f,                                                                                                           //      float                                   minSampleShading;
-               &sampleMask,                                                                                            //      const VkSampleMask*             pSampleMask;
-               DE_FALSE,                                                                                                       //      VkBool32                                alphaToCoverageEnable;
-               DE_FALSE,                                                                                                       //      VkBool32                                alphaToOneEnable;
-       };
-       const VkPipelineRasterizationStateCreateInfo    rasterParams            =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,     //      VkStructureType sType;
-               DE_NULL,                                                                                                        //      const void*             pNext;
-               (VkPipelineRasterizationStateCreateFlags)0,
-               DE_TRUE,                                                                                                        //      deUint32                depthClipEnable;
-               DE_FALSE,                                                                                                       //      deUint32                rasterizerDiscardEnable;
-               VK_POLYGON_MODE_FILL,                                                                           //      VkFillMode              fillMode;
-               VK_CULL_MODE_NONE,                                                                                      //      VkCullMode              cullMode;
-               VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                        //      VkFrontFace             frontFace;
-               VK_FALSE,                                                                                                       //      VkBool32                depthBiasEnable;
-               0.0f,                                                                                                           //      float                   depthBias;
-               0.0f,                                                                                                           //      float                   depthBiasClamp;
-               0.0f,                                                                                                           //      float                   slopeScaledDepthBias;
-               1.0f,                                                                                                           //      float                   lineWidth;
-       };
-       const VkPrimitiveTopology topology = 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,
-               topology,                                                                                                               //      VkPrimitiveTopology     topology;
-               DE_FALSE,                                                                                                               //      deUint32                        primitiveRestartEnable;
-       };
-       const VkVertexInputBindingDescription           vertexBinding0 =
-       {
-               0u,                                                                     // deUint32                                     binding;
-               deUint32(singleVertexDataSize),         // deUint32                                     strideInBytes;
-               VK_VERTEX_INPUT_RATE_VERTEX                     // VkVertexInputStepRate        stepRate;
-       };
-       const VkVertexInputAttributeDescription         vertexAttrib0[2] =
-       {
-               {
-                       0u,                                                                     // deUint32     location;
-                       0u,                                                                     // deUint32     binding;
-                       VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
-                       0u                                                                      // deUint32     offsetInBytes;
-               },
-               {
-                       1u,                                                                     // deUint32     location;
-                       0u,                                                                     // deUint32     binding;
-                       VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat     format;
-                       sizeof(Vec4),                                           // deUint32     offsetInBytes;
-               }
-       };
-
-       const VkPipelineVertexInputStateCreateInfo      vertexInputStateParams  =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,      //      VkStructureType                                                         sType;
-               DE_NULL,                                                                                                        //      const void*                                                                     pNext;
-               (VkPipelineVertexInputStateCreateFlags)0,
-               1u,                                                                                                                     //      deUint32                                                                        bindingCount;
-               &vertexBinding0,                                                                                        //      const VkVertexInputBindingDescription*          pVertexBindingDescriptions;
-               2u,                                                                                                                     //      deUint32                                                                        attributeCount;
-               vertexAttrib0,                                                                                          //      const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions;
-       };
-       const VkPipelineColorBlendAttachmentState       attBlendParams                  =
-       {
-               DE_FALSE,                                                                                                       //      deUint32                blendEnable;
-               VK_BLEND_FACTOR_ONE,                                                                            //      VkBlend                 srcBlendColor;
-               VK_BLEND_FACTOR_ZERO,                                                                           //      VkBlend                 destBlendColor;
-               VK_BLEND_OP_ADD,                                                                                        //      VkBlendOp               blendOpColor;
-               VK_BLEND_FACTOR_ONE,                                                                            //      VkBlend                 srcBlendAlpha;
-               VK_BLEND_FACTOR_ZERO,                                                                           //      VkBlend                 destBlendAlpha;
-               VK_BLEND_OP_ADD,                                                                                        //      VkBlendOp               blendOpAlpha;
-               (VK_COLOR_COMPONENT_R_BIT|
-                VK_COLOR_COMPONENT_G_BIT|
-                VK_COLOR_COMPONENT_B_BIT|
-                VK_COLOR_COMPONENT_A_BIT),                                                                     //      VkChannelFlags  channelWriteMask;
-       };
-       const VkPipelineColorBlendStateCreateInfo       blendParams                             =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       //      VkStructureType                                                         sType;
-               DE_NULL,                                                                                                        //      const void*                                                                     pNext;
-               (VkPipelineColorBlendStateCreateFlags)0,
-               DE_FALSE,                                                                                                       //      VkBool32                                                                        logicOpEnable;
-               VK_LOGIC_OP_COPY,                                                                                       //      VkLogicOp                                                                       logicOp;
-               1u,                                                                                                                     //      deUint32                                                                        attachmentCount;
-               &attBlendParams,                                                                                        //      const VkPipelineColorBlendAttachmentState*      pAttachments;
-               { 0.0f, 0.0f, 0.0f, 0.0f },                                                                     //      float                                                                           blendConst[4];
-       };
-       const VkPipelineTessellationStateCreateInfo     tessellationState       =
-       {
-               VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
-               DE_NULL,
-               (VkPipelineTessellationStateCreateFlags)0,
-               3u
-       };
-
-       const VkPipelineTessellationStateCreateInfo* tessellationInfo   =       hasTessellation ? &tessellationState: DE_NULL;
-       const VkGraphicsPipelineCreateInfo              pipelineParams                  =
-       {
-               VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,                //      VkStructureType                                                                 sType;
-               DE_NULL,                                                                                                //      const void*                                                                             pNext;
-               0u,                                                                                                             //      VkPipelineCreateFlags                                                   flags;
-               (deUint32)shaderStageParams.size(),                                             //      deUint32                                                                                stageCount;
-               &shaderStageParams[0],                                                                  //      const VkPipelineShaderStageCreateInfo*                  pStages;
-               &vertexInputStateParams,                                                                //      const VkPipelineVertexInputStateCreateInfo*             pVertexInputState;
-               &inputAssemblyParams,                                                                   //      const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState;
-               tessellationInfo,                                                                               //      const VkPipelineTessellationStateCreateInfo*    pTessellationState;
-               &viewportParams,                                                                                //      const VkPipelineViewportStateCreateInfo*                pViewportState;
-               &rasterParams,                                                                                  //      const VkPipelineRasterStateCreateInfo*                  pRasterState;
-               &multisampleParams,                                                                             //      const VkPipelineMultisampleStateCreateInfo*             pMultisampleState;
-               &depthStencilParams,                                                                    //      const VkPipelineDepthStencilStateCreateInfo*    pDepthStencilState;
-               &blendParams,                                                                                   //      const VkPipelineColorBlendStateCreateInfo*              pColorBlendState;
-               (const VkPipelineDynamicStateCreateInfo*)DE_NULL,               //      const VkPipelineDynamicStateCreateInfo*                 pDynamicState;
-               *pipelineLayout,                                                                                //      VkPipelineLayout                                                                layout;
-               *renderPass,                                                                                    //      VkRenderPass                                                                    renderPass;
-               0u,                                                                                                             //      deUint32                                                                                subpass;
-               DE_NULL,                                                                                                //      VkPipeline                                                                              basePipelineHandle;
-               0u,                                                                                                             //      deInt32                                                                                 basePipelineIndex;
-       };
-
-       const Unique<VkPipeline>                                pipeline                                (createGraphicsPipeline(vk, vkDevice, DE_NULL, &pipelineParams));
-
-       // Framebuffer
-       const VkFramebufferCreateInfo                   framebufferParams               =
-       {
-               VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                              //      VkStructureType         sType;
-               DE_NULL,                                                                                                //      const void*                     pNext;
-               (VkFramebufferCreateFlags)0,
-               *renderPass,                                                                                    //      VkRenderPass            renderPass;
-               1u,                                                                                                             //      deUint32                        attachmentCount;
-               &*colorAttView,                                                                                 //      const VkImageView*      pAttachments;
-               (deUint32)renderSize.x(),                                                               //      deUint32                        width;
-               (deUint32)renderSize.y(),                                                               //      deUint32                        height;
-               1u,                                                                                                             //      deUint32                        layers;
-       };
-       const Unique<VkFramebuffer>                             framebuffer                             (createFramebuffer(vk, vkDevice, &framebufferParams));
-
-       const Unique<VkCommandPool>                             cmdPool                                 (createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
-
-       // Command buffer
-       const Unique<VkCommandBuffer>                   cmdBuf                                  (allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
-
-       const VkCommandBufferBeginInfo                  cmdBufBeginParams               =
-       {
-               VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,                    //      VkStructureType                         sType;
-               DE_NULL,                                                                                                //      const void*                                     pNext;
-               (VkCommandBufferUsageFlags)0,
-               (const VkCommandBufferInheritanceInfo*)DE_NULL,
-       };
-
-       // Record commands
-       VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
-
-       {
-               const VkMemoryBarrier           vertFlushBarrier        =
-               {
-                       VK_STRUCTURE_TYPE_MEMORY_BARRIER,                       //      VkStructureType         sType;
-                       DE_NULL,                                                                        //      const void*                     pNext;
-                       VK_ACCESS_HOST_WRITE_BIT,                                       //      VkMemoryOutputFlags     outputMask;
-                       VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,            //      VkMemoryInputFlags      inputMask;
-               };
-               const VkImageMemoryBarrier      colorAttBarrier         =
-               {
-                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         //      VkStructureType                 sType;
-                       DE_NULL,                                                                        //      const void*                             pNext;
-                       0u,                                                                                     //      VkMemoryOutputFlags             outputMask;
-                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           //      VkMemoryInputFlags              inputMask;
-                       VK_IMAGE_LAYOUT_UNDEFINED,                                      //      VkImageLayout                   oldLayout;
-                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       //      VkImageLayout                   newLayout;
-                       queueFamilyIndex,                                                       //      deUint32                                srcQueueFamilyIndex;
-                       queueFamilyIndex,                                                       //      deUint32                                destQueueFamilyIndex;
-                       *image,                                                                         //      VkImage                                 image;
-                       {
-                               VK_IMAGE_ASPECT_COLOR_BIT,                                      //      VkImageAspect   aspect;
-                               0u,                                                                                     //      deUint32                baseMipLevel;
-                               1u,                                                                                     //      deUint32                mipLevels;
-                               0u,                                                                                     //      deUint32                baseArraySlice;
-                               1u,                                                                                     //      deUint32                arraySize;
-                       }                                                                                       //      VkImageSubresourceRange subresourceRange;
-               };
-               vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 1, &vertFlushBarrier, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &colorAttBarrier);
-       }
-
-       {
-               const VkClearValue                      clearValue              = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
-               const VkRenderPassBeginInfo     passBeginParams =
-               {
-                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                       //      VkStructureType         sType;
-                       DE_NULL,                                                                                        //      const void*                     pNext;
-                       *renderPass,                                                                            //      VkRenderPass            renderPass;
-                       *framebuffer,                                                                           //      VkFramebuffer           framebuffer;
-                       { { 0, 0 }, { renderSize.x(), renderSize.y() } },       //      VkRect2D                        renderArea;
-                       1u,                                                                                                     //      deUint32                        clearValueCount;
-                       &clearValue,                                                                            //      const VkClearValue*     pClearValues;
-               };
-               vk.cmdBeginRenderPass(*cmdBuf, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
-       }
-
-       vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
-       {
-               const VkDeviceSize bindingOffset = 0;
-               vk.cmdBindVertexBuffers(*cmdBuf, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
-       }
-       vk.cmdDraw(*cmdBuf, deUint32(vertexCount), 1u /*run pipeline once*/, 0u /*first vertex*/, 0u /*first instanceIndex*/);
-       vk.cmdEndRenderPass(*cmdBuf);
-
-       {
-               const VkImageMemoryBarrier      renderFinishBarrier     =
-               {
-                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         //      VkStructureType                 sType;
-                       DE_NULL,                                                                        //      const void*                             pNext;
-                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           //      VkMemoryOutputFlags             outputMask;
-                       VK_ACCESS_TRANSFER_READ_BIT,                            //      VkMemoryInputFlags              inputMask;
-                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       //      VkImageLayout                   oldLayout;
-                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,           //      VkImageLayout                   newLayout;
-                       queueFamilyIndex,                                                       //      deUint32                                srcQueueFamilyIndex;
-                       queueFamilyIndex,                                                       //      deUint32                                destQueueFamilyIndex;
-                       *image,                                                                         //      VkImage                                 image;
-                       {
-                               VK_IMAGE_ASPECT_COLOR_BIT,                                      //      VkImageAspectFlags      aspectMask;
-                               0u,                                                                                     //      deUint32                        baseMipLevel;
-                               1u,                                                                                     //      deUint32                        mipLevels;
-                               0u,                                                                                     //      deUint32                        baseArraySlice;
-                               1u,                                                                                     //      deUint32                        arraySize;
-                       }                                                                                       //      VkImageSubresourceRange subresourceRange;
-               };
-               vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &renderFinishBarrier);
-       }
-
-       {
-               const VkBufferImageCopy copyParams      =
-               {
-                       (VkDeviceSize)0u,                                               //      VkDeviceSize                    bufferOffset;
-                       (deUint32)renderSize.x(),                               //      deUint32                                bufferRowLength;
-                       (deUint32)renderSize.y(),                               //      deUint32                                bufferImageHeight;
-                       {
-                               VK_IMAGE_ASPECT_COLOR_BIT,                              //      VkImageAspect           aspect;
-                               0u,                                                                             //      deUint32                        mipLevel;
-                               0u,                                                                             //      deUint32                        arrayLayer;
-                               1u,                                                                             //      deUint32                        arraySize;
-                       },                                                                              //      VkImageSubresourceCopy  imageSubresource;
-                       { 0u, 0u, 0u },                                                 //      VkOffset3D                              imageOffset;
-                       { renderSize.x(), renderSize.y(), 1u }  //      VkExtent3D                              imageExtent;
-               };
-               vk.cmdCopyImageToBuffer(*cmdBuf, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
-       }
-
-       {
-               const VkBufferMemoryBarrier     copyFinishBarrier       =
-               {
-                       VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,        //      VkStructureType         sType;
-                       DE_NULL,                                                                        //      const void*                     pNext;
-                       VK_ACCESS_TRANSFER_WRITE_BIT,                           //      VkMemoryOutputFlags     outputMask;
-                       VK_ACCESS_HOST_READ_BIT,                                        //      VkMemoryInputFlags      inputMask;
-                       queueFamilyIndex,                                                       //      deUint32                        srcQueueFamilyIndex;
-                       queueFamilyIndex,                                                       //      deUint32                        destQueueFamilyIndex;
-                       *readImageBuffer,                                                       //      VkBuffer                        buffer;
-                       0u,                                                                                     //      VkDeviceSize            offset;
-                       imageSizeBytes                                                          //      VkDeviceSize            size;
-               };
-               vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &copyFinishBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
-       }
-
-       VK_CHECK(vk.endCommandBuffer(*cmdBuf));
-
-       // Upload vertex data
-       {
-               const VkMappedMemoryRange       range                   =
-               {
-                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
-                       DE_NULL,                                                                //      const void*             pNext;
-                       vertexBufferMemory->getMemory(),                //      VkDeviceMemory  mem;
-                       0,                                                                              //      VkDeviceSize    offset;
-                       (VkDeviceSize)sizeof(vertexData),               //      VkDeviceSize    size;
-               };
-               void*                                           vertexBufPtr    = vertexBufferMemory->getHostPtr();
-
-               deMemcpy(vertexBufPtr, &vertexData[0], sizeof(vertexData));
-               VK_CHECK(vk.flushMappedMemoryRanges(vkDevice, 1u, &range));
-       }
-
-       // Submit & wait for completion
-       {
-               const Unique<VkFence>   fence           (createFence(vk, vkDevice));
-               const VkSubmitInfo              submitInfo      =
-               {
-                       VK_STRUCTURE_TYPE_SUBMIT_INFO,
-                       DE_NULL,
-                       0u,
-                       (const VkSemaphore*)DE_NULL,
-                       (const VkPipelineStageFlags*)DE_NULL,
-                       1u,
-                       &cmdBuf.get(),
-                       0u,
-                       (const VkSemaphore*)DE_NULL,
-               };
-
-               VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
-               VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
-       }
-
-       const void* imagePtr    = readImageBufferMemory->getHostPtr();
-       const tcu::ConstPixelBufferAccess pixelBuffer(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
-                                                                                                 renderSize.x(), renderSize.y(), 1, imagePtr);
-       // Log image
-       {
-               const VkMappedMemoryRange       range           =
-               {
-                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  //      VkStructureType sType;
-                       DE_NULL,                                                                //      const void*             pNext;
-                       readImageBufferMemory->getMemory(),             //      VkDeviceMemory  mem;
-                       0,                                                                              //      VkDeviceSize    offset;
-                       imageSizeBytes,                                                 //      VkDeviceSize    size;
-               };
-
-               VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
-               context.getTestContext().getLog() << TestLog::Image("Result", "Result", pixelBuffer);
-       }
-
-       const RGBA threshold(1, 1, 1, 1);
-       const RGBA upperLeft(pixelBuffer.getPixel(1, 1));
-       if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold))
-               return TestStatus::fail("Upper left corner mismatch");
-
-       const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1));
-       if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold))
-               return TestStatus::fail("Upper right corner mismatch");
-
-       const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1));
-       if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold))
-               return TestStatus::fail("Lower left corner mismatch");
-
-       const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1));
-       if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold))
-               return TestStatus::fail("Lower right corner mismatch");
-
-       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, const vector<deInt32>& specConstants, tcu::TestCaseGroup* tests)
-{
-       const ShaderElement             vertFragPipelineStages[]                =
-       {
-               ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
-               ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
-       };
-
-       const ShaderElement             tessPipelineStages[]                    =
-       {
-               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("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
-       };
-
-       const ShaderElement             geomPipelineStages[]                            =
-       {
-               ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
-               ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
-               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(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
-
-       specConstantMap.clear();
-       specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants;
-       addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
-
-       specConstantMap.clear();
-       specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants;
-       addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
-
-       specConstantMap.clear();
-       specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants;
-       addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(geomPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
-
-       specConstantMap.clear();
-       specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants;
-       addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
-                                                                                                createInstanceContext(vertFragPipelineStages, 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
 
@@ -7047,7 +4832,6 @@ tcu::TestCaseGroup* createOpUndefTests(tcu::TestContext& testCtx)
        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"
@@ -7431,7 +5215,9 @@ tcu::TestCaseGroup* createModuleTests(tcu::TestContext& testCtx)
 
        getDefaultColors(defaultColors);
        getInvertedDefaultColors(invertedColors);
-       addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), "same_module", "", createCombinedModule, runAndVerifyDefaultPipeline, createInstanceContext(combinedPipeline, map<string, string>()));
+       addFunctionCaseWithPrograms<InstanceContext>(
+                       moduleTests.get(), "same_module", "", createCombinedModule, runAndVerifyDefaultPipeline,
+                       createInstanceContext(combinedPipeline, map<string, string>()));
 
        const char* numbers[] =
        {
@@ -7455,11 +5241,15 @@ tcu::TestCaseGroup* createModuleTests(tcu::TestContext& testCtx)
                // 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>()));
+                       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>()));
+                       addFunctionCaseWithPrograms<InstanceContext>(
+                                       moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline,
+                                       createInstanceContext(pipeline, defaultColors, invertedColors, map<string, string>()));
                }
        }
        return moduleTests.release();
@@ -7696,26 +5486,6 @@ tcu::TestCaseGroup* createLoopTests(tcu::TestContext& testCtx)
        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("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)
 {
@@ -8011,22 +5781,22 @@ bool usesInt64 (IntegerType from, IntegerType to)
                        || to == INTEGER_TYPE_SIGNED_64 || to == INTEGER_TYPE_UNSIGNED_64);
 }
 
-ConvertTestFeatures getUsedFeatures (IntegerType from, IntegerType to)
+ComputeTestFeatures getConversionUsedFeatures (IntegerType from, IntegerType to)
 {
        if (usesInt16(from, to))
        {
                if (usesInt64(from, to))
                {
-                       return CONVERT_TEST_USES_INT16_INT64;
+                       return COMPUTE_TEST_USES_INT16_INT64;
                }
                else
                {
-                       return CONVERT_TEST_USES_INT16;
+                       return COMPUTE_TEST_USES_INT16;
                }
        }
        else
        {
-               return CONVERT_TEST_USES_INT64;
+               return COMPUTE_TEST_USES_INT64;
        }
 }
 
@@ -8035,7 +5805,7 @@ struct ConvertCase
        ConvertCase (IntegerType from, IntegerType to, deInt64 number)
        : m_fromType            (from)
        , m_toType                      (to)
-       , m_features            (getUsedFeatures(from, to))
+       , m_features            (getConversionUsedFeatures(from, to))
        , m_name                        (getTestName(from, to))
        , m_inputBuffer         (getBuffer(from, number))
        , m_outputBuffer        (getBuffer(to, number))
@@ -8043,15 +5813,15 @@ struct ConvertCase
                m_asmTypes["inputType"]         = getAsmTypeDeclaration(from);
                m_asmTypes["outputType"]        = getAsmTypeDeclaration(to);
 
-               if (m_features == CONVERT_TEST_USES_INT16)
+               if (m_features == COMPUTE_TEST_USES_INT16)
                {
                        m_asmTypes["int_capabilities"] = "OpCapability Int16\n";
                }
-               else if (m_features == CONVERT_TEST_USES_INT64)
+               else if (m_features == COMPUTE_TEST_USES_INT64)
                {
                        m_asmTypes["int_capabilities"] = "OpCapability Int64\n";
                }
-               else if (m_features == CONVERT_TEST_USES_INT16_INT64)
+               else if (m_features == COMPUTE_TEST_USES_INT16_INT64)
                {
                        m_asmTypes["int_capabilities"] = string("OpCapability Int16\n") +
                                                                                                        "OpCapability Int64\n";
@@ -8064,7 +5834,7 @@ struct ConvertCase
 
        IntegerType                             m_fromType;
        IntegerType                             m_toType;
-       ConvertTestFeatures             m_features;
+       ComputeTestFeatures             m_features;
        string                                  m_name;
        map<string, string>             m_asmTypes;
        BufferSp                                m_inputBuffer;
@@ -8175,7 +5945,7 @@ tcu::TestCaseGroup* createSConvertTests (tcu::TestContext& testCtx)
                spec.outputs.push_back(test->m_outputBuffer);
                spec.numWorkGroups = IVec3(1, 1, 1);
 
-               group->addChild(new ConvertTestCase(testCtx, test->m_name.c_str(), "Convert integers with OpSConvert.", spec, test->m_features));
+               group->addChild(new SpvAsmComputeShaderCase(testCtx, test->m_name.c_str(), "Convert integers with OpSConvert.", spec, test->m_features));
        }
 
        return group.release();
@@ -8213,30 +5983,22 @@ tcu::TestCaseGroup* createUConvertTests (tcu::TestContext& testCtx)
                spec.outputs.push_back(test->m_outputBuffer);
                spec.numWorkGroups = IVec3(1, 1, 1);
 
-               group->addChild(new ConvertTestCase(testCtx, test->m_name.c_str(), "Convert integers with OpUConvert.", spec, test->m_features));
+               group->addChild(new SpvAsmComputeShaderCase(testCtx, test->m_name.c_str(), "Convert integers with OpUConvert.", spec, test->m_features));
        }
        return group.release();
 }
 
-enum NumberType
-{
-       TYPE_INT,
-       TYPE_UINT,
-       TYPE_FLOAT,
-       TYPE_END,
-};
-
 const string getNumberTypeName (const NumberType type)
 {
-       if (type == TYPE_INT)
+       if (type == NUMBERTYPE_INT32)
        {
                return "int";
        }
-       else if (type == TYPE_UINT)
+       else if (type == NUMBERTYPE_UINT32)
        {
                return "uint";
        }
-       else if (type == TYPE_FLOAT)
+       else if (type == NUMBERTYPE_FLOAT32)
        {
                return "float";
        }
@@ -8252,14 +6014,6 @@ deInt32 getInt(de::Random& rnd)
        return rnd.getInt(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
 }
 
-template <typename T>
-const string numberToString (T number)
-{
-       std::stringstream ss;
-       ss << number;
-       return ss.str();
-}
-
 const string repeatString (const string& str, int times)
 {
        string filler;
@@ -8272,15 +6026,15 @@ const string repeatString (const string& str, int times)
 
 const string getRandomConstantString (const NumberType type, de::Random& rnd)
 {
-       if (type == TYPE_INT)
+       if (type == NUMBERTYPE_INT32)
        {
                return numberToString<deInt32>(getInt(rnd));
        }
-       else if (type == TYPE_UINT)
+       else if (type == NUMBERTYPE_UINT32)
        {
                return numberToString<deUint32>(rnd.getUint32());
        }
-       else if (type == TYPE_FLOAT)
+       else if (type == NUMBERTYPE_FLOAT32)
        {
                return numberToString<float>(rnd.getFloat());
        }
@@ -8391,7 +6145,7 @@ void createCompositeCases (vector<map<string, string> >& testCases, de::Random&
        createArrayCompositeCases(testCases, rnd, type);
        createStructCompositeCases(testCases, rnd, type);
        // Matrix only supports float types
-       if (type == TYPE_FLOAT)
+       if (type == NUMBERTYPE_FLOAT32)
        {
                createMatrixCompositeCases(testCases, rnd, type);
        }
@@ -8401,9 +6155,9 @@ const string getAssemblyTypeDeclaration (const NumberType type)
 {
        switch (type)
        {
-               case TYPE_INT:          return "OpTypeInt 32 1";
-               case TYPE_UINT:         return "OpTypeInt 32 0";
-               case TYPE_FLOAT:        return "OpTypeFloat 32";
+               case NUMBERTYPE_INT32:          return "OpTypeInt 32 1";
+               case NUMBERTYPE_UINT32:         return "OpTypeInt 32 0";
+               case NUMBERTYPE_FLOAT32:        return "OpTypeFloat 32";
                default:                        DE_ASSERT(false); return "";
        }
 }
@@ -8498,7 +6252,7 @@ tcu::TestCaseGroup* createOpCompositeInsertGroup (tcu::TestContext& testCtx)
        de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "opcompositeinsert", "Test the OpCompositeInsert instruction"));
        de::Random                                              rnd             (deStringHash(group->getName()));
 
-       for (int type = TYPE_INT; type != TYPE_END; ++type)
+       for (int type = NUMBERTYPE_INT32; type != NUMBERTYPE_END32; ++type)
        {
                NumberType                                              numberType              = NumberType(type);
                const string                                    typeName                = getNumberTypeName(numberType);
@@ -8516,21 +6270,21 @@ tcu::TestCaseGroup* createOpCompositeInsertGroup (tcu::TestContext& testCtx)
 
                        switch (numberType)
                        {
-                               case TYPE_INT:
+                               case NUMBERTYPE_INT32:
                                {
                                        deInt32 number = getInt(rnd);
                                        spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
                                        spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
                                        break;
                                }
-                               case TYPE_UINT:
+                               case NUMBERTYPE_UINT32:
                                {
                                        deUint32 number = rnd.getUint32();
                                        spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
                                        spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
                                        break;
                                }
-                               case TYPE_FLOAT:
+                               case NUMBERTYPE_FLOAT32:
                                {
                                        float number = rnd.getFloat();
                                        spec.inputs.push_back(createCompositeBuffer<float>(number));
@@ -8676,7 +6430,7 @@ tcu::TestCaseGroup* createOpInBoundsAccessChainGroup (tcu::TestContext& testCtx)
        de::MovePtr<tcu::TestCaseGroup> group                   (new tcu::TestCaseGroup(testCtx, "opinboundsaccesschain", "Test the OpInBoundsAccessChain instruction"));
        de::Random                                              rnd                             (deStringHash(group->getName()));
 
-       for (int type = TYPE_INT; type != TYPE_END; ++type)
+       for (int type = NUMBERTYPE_INT32; type != NUMBERTYPE_END32; ++type)
        {
                NumberType                                              numberType      = NumberType(type);
                const string                                    typeName        = getNumberTypeName(numberType);
@@ -8700,21 +6454,21 @@ tcu::TestCaseGroup* createOpInBoundsAccessChainGroup (tcu::TestContext& testCtx)
 
                        switch (numberType)
                        {
-                               case TYPE_INT:
+                               case NUMBERTYPE_INT32:
                                {
                                        deInt32 number = getInt(rnd);
                                        spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
                                        spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
                                        break;
                                }
-                               case TYPE_UINT:
+                               case NUMBERTYPE_UINT32:
                                {
                                        deUint32 number = rnd.getUint32();
                                        spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
                                        spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
                                        break;
                                }
-                               case TYPE_FLOAT:
+                               case NUMBERTYPE_FLOAT32:
                                {
                                        float number = rnd.getFloat();
                                        spec.inputs.push_back(createCompositeBuffer<float>(number));
@@ -8856,7 +6610,7 @@ tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
        de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "shader_default_output", "Test shader default output."));
        de::Random                                              rnd             (deStringHash(group->getName()));
 
-       for (int type = TYPE_INT; type != TYPE_END; ++type)
+       for (int type = NUMBERTYPE_INT32; type != NUMBERTYPE_END32; ++type)
        {
                NumberType                                              numberType      = NumberType(type);
                const string                                    typeName        = getNumberTypeName(numberType);
@@ -8873,7 +6627,7 @@ tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
 
                        switch (numberType)
                        {
-                               case TYPE_INT:
+                               case NUMBERTYPE_INT32:
                                {
                                        deInt32 number = getInt(rnd);
                                        spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
@@ -8881,7 +6635,7 @@ tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
                                        params["constValue"] = numberToString(number);
                                        break;
                                }
-                               case TYPE_UINT:
+                               case NUMBERTYPE_UINT32:
                                {
                                        deUint32 number = rnd.getUint32();
                                        spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
@@ -8889,7 +6643,7 @@ tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
                                        params["constValue"] = numberToString(number);
                                        break;
                                }
-                               case TYPE_FLOAT:
+                               case NUMBERTYPE_FLOAT32:
                                {
                                        float number = rnd.getFloat();
                                        spec.inputs.push_back(createCompositeBuffer<float>(number));
@@ -8921,6 +6675,41 @@ tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
+tcu::TestCaseGroup* createOpNopTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "opnop", "Test OpNop"));
+       RGBA                                                    defaultColors[4];
+       map<string, string>                             opNopFragments;
+
+       getDefaultColors(defaultColors);
+
+       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, testGroup.get());
+
+       return testGroup.release();
+}
+
 tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> instructionTests        (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
@@ -8959,37 +6748,7 @@ tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
        computeTests->addChild(createOpInBoundsAccessChainGroup(testCtx));
        computeTests->addChild(createShaderDefaultOutputGroup(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(createOpNopTests(testCtx));
        graphicsTests->addChild(createOpSourceTests(testCtx));
        graphicsTests->addChild(createOpSourceContinuedTests(testCtx));
        graphicsTests->addChild(createOpLineTests(testCtx));
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.cpp
new file mode 100644 (file)
index 0000000..c4e225a
--- /dev/null
@@ -0,0 +1,151 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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 Utilities for Vulkan SPIR-V assembly tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmUtils.hpp"
+
+#include "deMemory.h"
+#include "deSTLUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+using namespace vk;
+
+namespace
+{
+
+VkPhysicalDeviceFeatures filterDefaultDeviceFeatures (const VkPhysicalDeviceFeatures& deviceFeatures)
+{
+       VkPhysicalDeviceFeatures enabledDeviceFeatures = deviceFeatures;
+
+       // Disable robustness by default, as it has an impact on performance on some HW.
+       enabledDeviceFeatures.robustBufferAccess = false;
+
+       return enabledDeviceFeatures;
+}
+
+} // anonymous
+
+bool is16BitStorageFeaturesSupported (const InstanceInterface& vki, VkPhysicalDevice device, const std::vector<std::string>& instanceExtensions, Extension16BitStorageFeatures toCheck)
+{
+       VkPhysicalDevice16BitStorageFeaturesKHR extensionFeatures       =
+       {
+               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,   // sType
+               DE_NULL,                                                                                                                // pNext
+               false,                                                                                                                  // storageUniformBufferBlock16
+               false,                                                                                                                  // storageUniform16
+               false,                                                                                                                  // storagePushConstant16
+               false,                                                                                                                  // storageInputOutput16
+       };
+       VkPhysicalDeviceFeatures2KHR                    features;
+
+       deMemset(&features, 0, sizeof(features));
+       features.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
+       features.pNext  = &extensionFeatures;
+
+       // Call the getter only if supported. Otherwise above "zero" defaults are used
+       if (de::contains(instanceExtensions.begin(), instanceExtensions.end(), "VK_KHR_get_physical_device_properties2"))
+       {
+               vki.getPhysicalDeviceFeatures2KHR(device, &features);
+       }
+
+       if ((toCheck & EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK) != 0 && extensionFeatures.storageUniformBufferBlock16 == VK_FALSE)
+               return false;
+
+       if ((toCheck & EXT16BITSTORAGEFEATURES_UNIFORM) != 0 && extensionFeatures.storageUniform16 == VK_FALSE)
+               return false;
+
+       if ((toCheck & EXT16BITSTORAGEFEATURES_PUSH_CONSTANT) != 0 && extensionFeatures.storagePushConstant16 == VK_FALSE)
+               return false;
+
+       if ((toCheck & EXT16BITSTORAGEFEATURES_INPUT_OUTPUT) != 0 && extensionFeatures.storageInputOutput16 == VK_FALSE)
+               return false;
+
+       return true;
+}
+
+Move<VkDevice> createDeviceWithExtensions (const InstanceInterface&                    vki,
+                                                                                  VkPhysicalDevice                                     physicalDevice,
+                                                                                  const deUint32                                       queueFamilyIndex,
+                                                                                  const std::vector<std::string>&      supportedExtensions,
+                                                                                  const std::vector<std::string>&      requiredExtensions)
+{
+       std::vector<const char*>                extensions                      (requiredExtensions.size());
+
+       for (deUint32 extNdx = 0; extNdx < requiredExtensions.size(); ++extNdx)
+       {
+               const std::string&      ext = requiredExtensions[extNdx];
+
+               // Check that all required extensions are supported first.
+               if (!de::contains(supportedExtensions.begin(), supportedExtensions.end(), ext))
+               {
+                       TCU_THROW(NotSupportedError, (std::string("Device extension not supported: ") + ext).c_str());
+               }
+
+               extensions[extNdx] = ext.c_str();
+       }
+
+       const float                                             queuePriorities[]       = { 1.0f };
+       const VkDeviceQueueCreateInfo   queueInfos[]            =
+       {
+               {
+                       VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                       DE_NULL,
+                       (VkDeviceQueueCreateFlags)0,
+                       queueFamilyIndex,
+                       DE_LENGTH_OF_ARRAY(queuePriorities),
+                       &queuePriorities[0]
+               }
+       };
+       const VkPhysicalDeviceFeatures  features                        = filterDefaultDeviceFeatures(getPhysicalDeviceFeatures(vki, physicalDevice));
+       const VkDeviceCreateInfo                deviceParams            =
+       {
+               VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+               DE_NULL,
+               (VkDeviceCreateFlags)0,
+               DE_LENGTH_OF_ARRAY(queueInfos),
+               &queueInfos[0],
+               0u,
+               DE_NULL,
+               (deUint32)extensions.size(),
+               extensions.empty() ? DE_NULL : &extensions[0],
+               &features
+       };
+
+       return vk::createDevice(vki, physicalDevice, &deviceParams);
+}
+
+Allocator* createAllocator (const InstanceInterface& instanceInterface, const VkPhysicalDevice physicalDevice, const DeviceInterface& deviceInterface, const VkDevice device)
+{
+       const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(instanceInterface, physicalDevice);
+
+       // \todo [2015-07-24 jarkko] support allocator selection/configuration from command line (or compile time)
+       return new SimpleAllocator(deviceInterface, device, memoryProperties);
+}
+
+} // SpirVAssembly
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmUtils.hpp
new file mode 100644 (file)
index 0000000..78c363f
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _VKTSPVASMUTILS_HPP
+#define _VKTSPVASMUTILS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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 Utilities for Vulkan SPIR-V assembly tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkMemUtil.hpp"
+#include "vkRef.hpp"
+#include "vkTypeUtil.hpp"
+
+#include <string>
+#include <vector>
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+enum Extension16BitStorageFeatureBits
+{
+       EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK    = (1u << 1),
+       EXT16BITSTORAGEFEATURES_UNIFORM                                 = (1u << 2),
+       EXT16BITSTORAGEFEATURES_PUSH_CONSTANT                   = (1u << 3),
+       EXT16BITSTORAGEFEATURES_INPUT_OUTPUT                    = (1u << 4),
+};
+typedef deUint32 Extension16BitStorageFeatures;
+
+struct ExtensionFeatures
+{
+       Extension16BitStorageFeatures   ext16BitStorage;
+
+       ExtensionFeatures       (void)
+               : ext16BitStorage       (0)
+       {}
+       explicit ExtensionFeatures      (Extension16BitStorageFeatures  ext16BitStorage_)
+               : ext16BitStorage       (ext16BitStorage_)
+       {}
+};
+
+// Returns true if the given 16bit storage extension features in `toCheck` are all supported.
+bool is16BitStorageFeaturesSupported (const vk::InstanceInterface&     vkInstance,
+                                                                         vk::VkPhysicalDevice                  device,
+                                                                         const std::vector<std::string>& instanceExtensions,
+                                                                         Extension16BitStorageFeatures toCheck);
+
+// Creates a Vulkan logical device with the requiredExtensions enabled and all other extensions disabled.
+// The logical device will be created from the given instance and physical device. A single queue will
+// be created from the given queue family.
+vk::Move<vk::VkDevice> createDeviceWithExtensions (const vk::InstanceInterface&                vki,
+                                                                                                  vk::VkPhysicalDevice                         physicalDevice,
+                                                                                                  deUint32                                                     queueFamilyIndex,
+                                                                                                  const std::vector<std::string>&      supportedExtensions,
+                                                                                                  const std::vector<std::string>&      requiredExtensions);
+
+// Creates a SimpleAllocator on the given device.
+vk::Allocator* createAllocator (const vk::InstanceInterface& instanceInterface,
+                                                               const vk::VkPhysicalDevice physicalDevice,
+                                                               const vk::DeviceInterface& deviceInterface,
+                                                               const vk::VkDevice device);
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMUTILS_HPP
index 11238cb..8f18a78 100644 (file)
@@ -224,6 +224,7 @@ typedef enum VkStructureType {
     VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000,
     VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
     VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
     VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
@@ -3953,6 +3954,19 @@ VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(
     const VkWriteDescriptorSet*                 pDescriptorWrites);
 #endif
 
+#define VK_KHR_16bit_storage 1
+#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
+#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
+
+typedef struct VkPhysicalDevice16BitStorageFeaturesKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           storageUniformBufferBlock16;
+    VkBool32           storageUniform16;
+    VkBool32           storagePushConstant16;
+    VkBool32           storageInputOutput16;
+} VkPhysicalDevice16BitStorageFeaturesKHR;
+
 #define VK_KHR_incremental_present 1
 #define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
 #define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"