Merge "CTS v2 integration for deqp"
am: 6f483cc3fa

* commit '6f483cc3fa820e58ed9f83c83bdf8d213293b3ad':
  CTS v2 integration for deqp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9760d72..fdd9d17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,12 @@
 	# \note PNG_LIBRARY and PNG_INCLUDE_PATH are promoted from external/libpng/CMakeLists.txt
 endif ()
 
+# glslang
+add_subdirectory(external/glslang)
+
+# spirv-tools
+add_subdirectory(external/spirv-tools)
+
 include_directories(${PNG_INCLUDE_PATH})
 
 message(STATUS "DEQP_TARGET_NAME        = ${DEQP_TARGET_NAME}")
@@ -186,6 +192,7 @@
 	framework/randomshaders
 	framework/egl
 	framework/egl/wrapper
+	external/vulkancts/framework/vulkan
 	)
 
 if (DE_OS_IS_ANDROID OR DE_OS_IS_IOS)
@@ -268,12 +275,14 @@
 endmacro (add_data_file)
 
 add_subdirectory(framework)
+add_subdirectory(external/vulkancts/framework/vulkan)
 
 if (DE_COMPILER_IS_MSC)
 	add_compile_options(/bigobj) # Required by glsBuiltinPrecisionTests.cpp
 endif ()
 
 add_subdirectory(modules)
+add_subdirectory(external/vulkancts/modules/vulkan)
 
 # Single-binary targets
 if (DE_OS_IS_ANDROID)
diff --git a/android/scripts/common.py b/android/scripts/common.py
index 888f4de..2611d9e 100644
--- a/android/scripts/common.py
+++ b/android/scripts/common.py
@@ -236,7 +236,7 @@
 		NativeLib(21,		"arm64-v8a",	'android-arm64'),	# ARM64 v8a ABI
 	]
 
-ANDROID_JAVA_API		= "android-13"
+ANDROID_JAVA_API		= "android-22"
 NATIVE_LIB_NAME			= "libdeqp.so"
 
 def selectNDKPath ():
diff --git a/doc/testspecs/VK/.gitignore b/doc/testspecs/VK/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/doc/testspecs/VK/.gitignore
@@ -0,0 +1 @@
+*.html
diff --git a/doc/testspecs/VK/apitests-docinfo.html b/doc/testspecs/VK/apitests-docinfo.html
new file mode 100644
index 0000000..69b8c61
--- /dev/null
+++ b/doc/testspecs/VK/apitests-docinfo.html
@@ -0,0 +1,23 @@
+<style type="text/css">
+
+code,div.listingblock {
+	max-width: 68em;
+}
+
+p {
+    max-width: 50em;
+}
+
+table {
+    max-width: 50em;
+}
+
+table.tableblock {
+  border-width: 1px;
+}
+
+h2 {
+    max-width: 35em;
+}
+
+</style>
diff --git a/doc/testspecs/VK/apitests.adoc b/doc/testspecs/VK/apitests.adoc
new file mode 100644
index 0000000..8db7021
--- /dev/null
+++ b/doc/testspecs/VK/apitests.adoc
@@ -0,0 +1,2776 @@
+// asciidoc -b html5 -d book -f apitests.conf apitests.adoc
+
+:toc:
+:numbered:
+:docinfo:
+:revnumber: 4
+
+Vulkan API Test Plan
+====================
+
+NOTE: Document currently targets API revision 0.138.0
+
+This document currently outlines Vulkan API testing plan. The document splits API into features, and for each the important testing objectives are described. The technical implementation is not currently planned or documented here, except in select cases.
+
+In the future this document will likely evolve into a description of various tests and test coverage.
+
+Test framework
+--------------
+
+Test framework will provide tests access to Vulkan platform interface. In addition a library of generic utilties will be provided.
+
+Test case base class
+~~~~~~~~~~~~~~~~~~~~
+
+Vulkan test cases will use a slightly different interface from traditional +tcu::TestCase+ to facilitate following:
+
+ * Ability to generate shaders in high-level language, and pre-compile them without running the tests
+ * Cleaner separation between test case parameters and execution instance
+
+[source,cpp]
+----
+class TestCase : public tcu::TestCase
+{
+public:
+                            TestCase        (tcu::TestContext& testCtx, const std::string& name, const std::string& description);
+                            TestCase        (tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& description);
+    virtual                 ~TestCase       (void) {}
+
+    virtual void            initPrograms    (vk::ProgramCollection<glu::ProgramSources>& programCollection) const;
+    virtual TestInstance*   createInstance  (Context& context) const = 0;
+
+    IterateResult           iterate         (void) { DE_ASSERT(false); return STOP; } // Deprecated in this module
+};
+
+class TestInstance
+{
+public:
+                                TestInstance    (Context& context) : m_context(context) {}
+    virtual                     ~TestInstance   (void) {}
+
+    virtual tcu::TestStatus     iterate         (void) = 0;
+
+protected:
+    Context&                    m_context;
+};
+----
+
+In addition for simple tests a utility to wrap a function as a test case is provided:
+
+[source,cpp]
+----
+tcu::TestStatus createSamplerTest (Context& context)
+{
+    TestLog&                log         = context.getTestContext().getLog();
+    const DefaultDevice     device      (context.getPlatformInterface(), context.getTestContext().getCommandLine());
+    const VkDevice          vkDevice    = device.getDevice();
+    const DeviceInterface&  vk          = device.getInterface();
+
+    {
+        const struct VkSamplerCreateInfo        samplerInfo =
+        {
+            VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,  //  VkStructureType sType;
+            DE_NULL,                                //  const void*     pNext;
+            VK_TEX_FILTER_NEAREST,                  //  VkTexFilter     magFilter;
+            VK_TEX_FILTER_NEAREST,                  //  VkTexFilter     minFilter;
+            VK_TEX_MIPMAP_MODE_BASE,                //  VkTexMipmapMode mipMode;
+            VK_TEX_ADDRESS_CLAMP,                   //  VkTexAddress    addressU;
+            VK_TEX_ADDRESS_CLAMP,                   //  VkTexAddress    addressV;
+            VK_TEX_ADDRESS_CLAMP,                   //  VkTexAddress    addressW;
+            0.0f,                                   //  float           mipLodBias;
+            0u,                                     //  deUint32        maxAnisotropy;
+            VK_COMPARE_OP_ALWAYS,                   //  VkCompareOp     compareOp;
+            0.0f,                                   //  float           minLod;
+            0.0f,                                   //  float           maxLod;
+            VK_BORDER_COLOR_TRANSPARENT_BLACK,      //  VkBorderColor   borderColor;
+        };
+
+        Move<VkSamplerT>    tmpSampler  = createSampler(vk, vkDevice, &samplerInfo);
+    }
+
+    return tcu::TestStatus::pass("Creating sampler succeeded");
+}
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+    de::MovePtr<tcu::TestCaseGroup> apiTests    (new tcu::TestCaseGroup(testCtx, "api", "API Tests"));
+    
+    addFunctionCase(apiTests.get(), "create_sampler",   "", createSamplerTest);
+
+    return apiTests.release();
+}
+----
+
++vkt::Context+, which is passed to +vkt::TestInstance+ will provide access to Vulkan platform interface, and a default device instance. Most test cases should use default device instance:
+
+ * Creating device can take up to tens of milliseconds
+ * --deqp-vk-device-id=N command line option can be used to change device
+ * Framework can force validation layers (--deqp-vk-layers=validation,...)
+
+Other considerations:
+
+ * Rather than using default header, deqp uses custom header & interface wrappers
+ ** See +vk::PlatformInterface+ and +vk::DeviceInterface+
+ ** Enables optional run-time dependency to Vulkan driver (required for Android, useful in general)
+ ** Various logging & other analysis facilities can be layered on top of that interface
+ * Expose validation state to tests to be able to test validation
+ * Extensions are opt-in, some tests will require certain extensions to work
+ ** --deqp-vk-extensions? enable all by default?
+ ** Probably good to be able to override extensions as well (verify that tests report correct results without extensions)
+
+Common utilities
+~~~~~~~~~~~~~~~~
+
+Test case independent Vulkan utilities will be provided in +vk+ namespace, and can be found under +framework/vulkan+. These include:
+
+ * +Unique<T>+ and +Move<T>+ wrappers for Vulkan API objects
+ * Creating all types of work with configurable parameters:
+ ** Workload "size" (not really comparable between types)
+ ** Consume & produce memory contents
+ *** Simple checksumming / other verification against reference data typically fine
+
+.TODO
+ * Document important utilities (vkRef.hpp for example).
+ * Document Vulkan platform port.
+
+Object management
+-----------------
+
+Object management tests verify that the driver is able to create and destroy objects of all types. The tests don't attempt to use the objects (unless necessary for testing object construction) as that is covered by feature-specific tests. For all object types the object management tests cover:
+
+ * Creating objects with a relevant set of parameters
+ ** Not exhaustive, guided by what might actually make driver to take different path
+ * Allocating multiple objects of same type
+ ** Reasonable limit depends on object type
+ * Creating objects from multiple threads concurrently (where possible)
+ * Freeing objects from multiple threads
+
+NOTE: tests for various +vkCreate*()+ functions are documented in feature-specific sections.
+
+Multithreaded scaling
+---------------------
+
+Vulkan API is free-threaded and suggests that many operations (such as constructing command buffers) will scale with number of app threads. Tests are needed for proving that such scalability actually exists, and there are no locks in important functionality preventing that.
+
+NOTE: Khronos CTS has not traditionally included any performance testing, and the tests may not be part of conformance criteria. The tests may however be useful for IHVs for driver optimization, and could be enforced by platform-specific conformance tests, such as Android CTS.
+
+Destructor functions
+~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+VkResult VKAPI vkDestroyInstance(
+    VkInstance                                  instance);
+
+VkResult VKAPI vkDestroyDevice(
+    VkDevice                                    device);
+
+VkResult VKAPI vkDestroyFence(
+    VkDevice                                    device,
+    VkFence                                     fence);
+
+VkResult VKAPI vkDestroySemaphore(
+    VkDevice                                    device,
+    VkSemaphore                                 semaphore);
+
+VkResult VKAPI vkDestroyEvent(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VkResult VKAPI vkDestroyQueryPool(
+    VkDevice                                    device,
+    VkQueryPool                                 queryPool);
+
+VkResult VKAPI vkDestroyBuffer(
+    VkDevice                                    device,
+    VkBuffer                                    buffer);
+
+VkResult VKAPI vkDestroyBufferView(
+    VkDevice                                    device,
+    VkBufferView                                bufferView);
+
+VkResult VKAPI vkDestroyImage(
+    VkDevice                                    device,
+    VkImage                                     image);
+
+VkResult VKAPI vkDestroyImageView(
+    VkDevice                                    device,
+    VkImageView                                 imageView);
+
+VkResult VKAPI vkDestroyAttachmentView(
+    VkDevice                                    device,
+    VkAttachmentView                            attachmentView);
+
+VkResult VKAPI vkDestroyShaderModule(
+    VkDevice                                    device,
+    VkShaderModule                              shaderModule);
+
+VkResult VKAPI vkDestroyShader(
+    VkDevice                                    device,
+    VkShader                                    shader);
+
+VkResult VKAPI vkDestroyPipelineCache(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache);
+
+VkResult VKAPI vkDestroyPipeline(
+    VkDevice                                    device,
+    VkPipeline                                  pipeline);
+
+VkResult VKAPI vkDestroyPipelineLayout(
+    VkDevice                                    device,
+    VkPipelineLayout                            pipelineLayout);
+
+VkResult VKAPI vkDestroySampler(
+    VkDevice                                    device,
+    VkSampler                                   sampler);
+
+VkResult VKAPI vkDestroyDescriptorSetLayout(
+    VkDevice                                    device,
+    VkDescriptorSetLayout                       descriptorSetLayout);
+
+VkResult VKAPI vkDestroyDescriptorPool(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool);
+
+VkResult VKAPI vkDestroyDynamicViewportState(
+    VkDevice                                    device,
+    VkDynamicViewportState                      dynamicViewportState);
+
+VkResult VKAPI vkDestroyDynamicRasterState(
+    VkDevice                                    device,
+    VkDynamicRasterState                        dynamicRasterState);
+
+VkResult VKAPI vkDestroyDynamicColorBlendState(
+    VkDevice                                    device,
+    VkDynamicColorBlendState                    dynamicColorBlendState);
+
+VkResult VKAPI vkDestroyDynamicDepthStencilState(
+    VkDevice                                    device,
+    VkDynamicDepthStencilState                  dynamicDepthStencilState);
+
+VkResult VKAPI vkDestroyFramebuffer(
+    VkDevice                                    device,
+    VkFramebuffer                               framebuffer);
+
+VkResult VKAPI vkDestroyRenderPass(
+    VkDevice                                    device,
+    VkRenderPass                                renderPass);
+
+VkResult VKAPI vkDestroyCommandPool(
+    VkDevice                                    device,
+    VkCmdPool                                   cmdPool);
+
+VkResult VKAPI vkDestroyCommandBuffer(
+    VkDevice                                    device,
+    VkCmdBuffer                                 commandBuffer);
+----
+
+API Queries
+-----------
+
+Objective of API query tests is to validate that various +vkGet*+ functions return correct values. Generic checks that apply to all query types are:
+
+ * Returned value size is equal or multiple of relevant struct size
+ * Query doesn't write outside the provided pointer
+ * Query values (where expected) don't change between subsequent queries
+ * Concurrent queries from multiple threads work
+
+Platform queries
+~~~~~~~~~~~~~~~~
+
+Platform query tests will validate that all queries work as expected and return sensible values.
+
+ * Sensible device properties
+ ** May have some Android-specific requirements
+ *** TBD queue 0 must be universal queue (all command types supported)
+ * All required functions present
+ ** Both platform (physicalDevice = 0) and device-specific
+ ** Culled based on enabled extension list?
+
+[source,c]
+----
+// Physical devices
+
+VkResult VKAPI vkEnumeratePhysicalDevices(
+    VkInstance                                  instance,
+    uint32_t*                                   pPhysicalDeviceCount,
+    VkPhysicalDevice*                           pPhysicalDevices);
+
+VkResult VKAPI vkGetPhysicalDeviceFeatures(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures*                   pFeatures);
+
+// Properties & limits
+
+VkResult VKAPI vkGetPhysicalDeviceLimits(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceLimits*                     pLimits);
+
+typedef struct {
+    uint32_t                                    apiVersion;
+    uint32_t                                    driverVersion;
+    uint32_t                                    vendorId;
+    uint32_t                                    deviceId;
+    VkPhysicalDeviceType                        deviceType;
+    char                                        deviceName[VK_MAX_PHYSICAL_DEVICE_NAME];
+    uint8_t                                     pipelineCacheUUID[VK_UUID_LENGTH];
+} VkPhysicalDeviceProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties*                 pProperties);
+
+// Queue properties
+
+VkResult VKAPI vkGetPhysicalDeviceQueueCount(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pCount);
+
+typedef enum {
+    VK_QUEUE_GRAPHICS_BIT = 0x00000001,
+    VK_QUEUE_COMPUTE_BIT = 0x00000002,
+    VK_QUEUE_DMA_BIT = 0x00000004,
+    VK_QUEUE_SPARSE_MEMMGR_BIT = 0x00000008,
+    VK_QUEUE_EXTENDED_BIT = 0x40000000,
+} VkQueueFlagBits;
+typedef VkFlags VkQueueFlags;
+
+typedef struct {
+    VkQueueFlags                                queueFlags;
+    uint32_t                                    queueCount;
+    VkBool32                                    supportsTimestamps;
+} VkPhysicalDeviceQueueProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceQueueProperties(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t                                    count,
+    VkPhysicalDeviceQueueProperties*            pQueueProperties);
+
+// Memory properties
+
+typedef enum {
+    VK_MEMORY_PROPERTY_DEVICE_ONLY = 0,
+    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000001,
+    VK_MEMORY_PROPERTY_HOST_NON_COHERENT_BIT = 0x00000002,
+    VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT = 0x00000004,
+    VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT = 0x00000008,
+    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
+} VkMemoryPropertyFlagBits;
+typedef VkFlags VkMemoryPropertyFlags;
+
+typedef enum {
+    VK_MEMORY_HEAP_HOST_LOCAL = 0x00000001,
+} VkMemoryHeapFlagBits;
+typedef VkFlags VkMemoryHeapFlags;
+
+typedef struct {
+    VkMemoryPropertyFlags                       propertyFlags;
+    uint32_t                                    heapIndex;
+} VkMemoryType;
+
+typedef struct {
+    VkDeviceSize                                size;
+    VkMemoryHeapFlags                           flags;
+} VkMemoryHeap;
+
+typedef struct {
+    uint32_t                                    memoryTypeCount;
+    VkMemoryType                                memoryTypes[VK_MAX_MEMORY_TYPES];
+    uint32_t                                    memoryHeapCount;
+    VkMemoryHeap                                memoryHeaps[VK_MAX_MEMORY_HEAPS];
+} VkPhysicalDeviceMemoryProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceMemoryProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties*           pMemoryProperties);
+
+// Proc address queries
+
+PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(
+    VkInstance                                  instance,
+    const char*                                 pName);
+
+PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(
+    VkDevice                                    device,
+    const char*                                 pName);
+
+// Extension queries
+
+typedef struct {
+    char                                        extName[VK_MAX_EXTENSION_NAME];
+    uint32_t                                    specVersion;
+} VkExtensionProperties;
+
+VkResult VKAPI vkGetGlobalExtensionProperties(
+    const char*                                 pLayerName,
+    uint32_t*                                   pCount,
+    VkExtensionProperties*                      pProperties);
+
+VkResult VKAPI vkGetPhysicalDeviceExtensionProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const char*                                 pLayerName,
+    uint32_t*                                   pCount,
+    VkExtensionProperties*                      pProperties);
+
+// Layer queries
+
+typedef struct {
+    char                                        layerName[VK_MAX_EXTENSION_NAME];
+    uint32_t                                    specVersion;
+    uint32_t                                    implVersion;
+    const char*                                 description[VK_MAX_DESCRIPTION];
+} VkLayerProperties;
+
+VkResult VKAPI vkGetGlobalLayerProperties(
+    uint32_t*                                   pCount,
+    VkLayerProperties*                          pProperties);
+
+VkResult VKAPI vkGetPhysicalDeviceLayerProperties(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pCount,
+    VkLayerProperties*                          pProperties);
+----
+
+Device queries
+~~~~~~~~~~~~~~
+
+[source,c]
+----
+VkResult VKAPI vkGetDeviceQueue(
+    VkDevice                                    device,
+    uint32_t                                    queueFamilyIndex,
+    uint32_t                                    queueIndex,
+    VkQueue*                                    pQueue);
+
+VkResult VKAPI vkGetDeviceMemoryCommitment(
+    VkDevice                                    device,
+    VkDeviceMemory                              memory,
+    VkDeviceSize*                               pCommittedMemoryInBytes);
+----
+
+Object queries
+~~~~~~~~~~~~~~
+
+ * Memory requirements: verify that for buffers the returned size is at least the size of the buffer
+
+[source,c]
+----
+typedef struct {
+    VkDeviceSize                                size;
+    VkDeviceSize                                alignment;
+    uint32_t                                    memoryTypeBits;
+} VkMemoryRequirements;
+
+VkResult VKAPI vkGetBufferMemoryRequirements(
+    VkDevice                                    device,
+    VkBuffer                                    buffer,
+    VkMemoryRequirements*                       pMemoryRequirements);
+
+VkResult VKAPI vkGetImageMemoryRequirements(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkMemoryRequirements*                       pMemoryRequirements);
+----
+
+Format & image capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef enum {
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001,
+    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002,
+    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004,
+    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008,
+    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010,
+    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020,
+    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040,
+    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080,
+    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100,
+    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200,
+    VK_FORMAT_FEATURE_CONVERSION_BIT = 0x00000400,
+} VkFormatFeatureFlagBits;
+typedef VkFlags VkFormatFeatureFlags;
+
+typedef struct {
+    VkFormatFeatureFlags                        linearTilingFeatures;
+    VkFormatFeatureFlags                        optimalTilingFeatures;
+} VkFormatProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties*                         pFormatProperties);
+
+typedef struct {
+    uint64_t                                    maxResourceSize;
+    uint32_t                                    maxSamples;
+} VkImageFormatProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceImageFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    VkImageTiling                               tiling,
+    VkImageUsageFlags                           usage,
+    VkImageFormatProperties*                    pImageFormatProperties);
+----
+
+Memory management
+-----------------
+
+Memory management tests cover memory allocation, sub-allocation, access, and CPU and GPU cache control. Testing some areas such as cache control will require stress-testing memory accesses from CPU and various pipeline stages.
+
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkDeviceSize                                allocationSize;
+    uint32_t                                    memoryTypeIndex;
+} VkMemoryAllocInfo;
+
+VkResult VKAPI vkAllocMemory(
+    VkDevice                                    device,
+    const VkMemoryAllocInfo*                    pAllocInfo,
+    VkDeviceMemory*                             pMem);
+
+VkResult VKAPI vkFreeMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              mem);
+----
+
+ * Test combination of:
+ ** Various allocation sizes
+ ** All heaps
+ * Allocations that exceed total available memory size (expected to fail)
+ * Concurrent allocation and free from multiple threads
+ * Memory leak tests (may not work on platforms that overcommit)
+ ** Allocate memory until fails, free all and repeat
+ ** Total allocated memory size should remain stable over iterations
+ ** Allocate and free in random order
+
+.Spec issues
+
+What are the alignment guarantees for the returned memory allocation? Will it satisfy alignment requirements for all object types? If not, app needs to know the alignment, or alignment parameter needs to be added to +VkMemoryAllocInfo+.
+
+Minimum allocation size? If 1, presumably implementation has to round it up to next page size at least? Is there a query for that? What happens when accessing the added padding?
+
+Mapping memory and CPU access
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+VkResult VKAPI vkMapMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              mem,
+    VkDeviceSize                                offset,
+    VkDeviceSize                                size,
+    VkMemoryMapFlags                            flags,
+    void**                                      ppData);
+
+VkResult VKAPI vkUnmapMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              mem);
+----
+
+ * Verify that mapping of all host-visible allocations succeed and accessing memory works
+ * Verify mapping of sub-ranges
+ * Access still works after un-mapping and re-mapping memory
+ * Attaching or detaching memory allocation from buffer/image doesn't affect mapped memory access or contents
+ ** Images: test with various formats, mip-levels etc.
+
+.Spec issues
+ * Man pages say vkMapMemory is thread-safe, but to what extent?
+ ** Mapping different VkDeviceMemory allocs concurrently?
+ ** Mapping different sub-ranges of same VkDeviceMemory?
+ ** Mapping overlapping sub-ranges of same VkDeviceMemory?
+ * Okay to re-map same or overlapping range? What pointers should be returned in that case?
+ * Can re-mapping same block return different virtual address?
+ * Alignment of returned CPU pointer?
+ ** Access using SIMD instructions can benefit from alignment
+
+CPU cache control
+~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkDeviceMemory                              mem;
+    VkDeviceSize                                offset;
+    VkDeviceSize                                size;
+} VkMappedMemoryRange;
+
+VkResult VKAPI vkFlushMappedMemoryRanges(
+    VkDevice                                    device,
+    uint32_t                                    memRangeCount,
+    const VkMappedMemoryRange*                  pMemRanges);
+
+VkResult VKAPI vkInvalidateMappedMemoryRanges(
+    VkDevice                                    device,
+    uint32_t                                    memRangeCount,
+    const VkMappedMemoryRange*                  pMemRanges);
+----
+
+ * TODO Semantics discussed at https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13690
+ ** Invalidate relevant for HOST_NON_COHERENT_BIT, flushes CPU read caches
+ ** Flush flushes CPU write caches?
+ * Test behavior with all possible mem alloc types & various sizes
+ * Corner-cases:
+ ** Empty list
+ ** Empty ranges
+ ** Same range specified multiple times
+ ** Partial overlap between ranges
+
+.Spec issues
+ * Thread-safety? Okay to flush different ranges concurrently?
+
+GPU cache control
+~~~~~~~~~~~~~~~~~
+
+Validate that GPU caches are invalidated where instructed. This includes visibility of memory writes made by both CPU and GPU to both CPU and GPU pipeline stages.
+
+[source,c]
+----
+typedef enum {
+    VK_MEMORY_OUTPUT_HOST_WRITE_BIT = 0x00000001,
+    VK_MEMORY_OUTPUT_SHADER_WRITE_BIT = 0x00000002,
+    VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT = 0x00000004,
+    VK_MEMORY_OUTPUT_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000008,
+    VK_MEMORY_OUTPUT_TRANSFER_BIT = 0x00000010,
+} VkMemoryOutputFlagBits;
+typedef VkFlags VkMemoryOutputFlags;
+
+typedef enum {
+    VK_MEMORY_INPUT_HOST_READ_BIT = 0x00000001,
+    VK_MEMORY_INPUT_INDIRECT_COMMAND_BIT = 0x00000002,
+    VK_MEMORY_INPUT_INDEX_FETCH_BIT = 0x00000004,
+    VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT = 0x00000008,
+    VK_MEMORY_INPUT_UNIFORM_READ_BIT = 0x00000010,
+    VK_MEMORY_INPUT_SHADER_READ_BIT = 0x00000020,
+    VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT = 0x00000040,
+    VK_MEMORY_INPUT_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000080,
+    VK_MEMORY_INPUT_INPUT_ATTACHMENT_BIT = 0x00000100,
+    VK_MEMORY_INPUT_TRANSFER_BIT = 0x00000200,
+} VkMemoryInputFlagBits;
+typedef VkFlags VkMemoryInputFlags;
+
+typedef enum {
+    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001,
+    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002,
+    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004,
+    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008,
+    VK_PIPELINE_STAGE_TESS_CONTROL_SHADER_BIT = 0x00000010,
+    VK_PIPELINE_STAGE_TESS_EVALUATION_SHADER_BIT = 0x00000020,
+    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040,
+    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080,
+    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100,
+    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200,
+    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400,
+    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800,
+    VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000,
+    VK_PIPELINE_STAGE_TRANSITION_BIT = 0x00002000,
+    VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
+    VK_PIPELINE_STAGE_ALL_GRAPHICS = 0x000007FF,
+    VK_PIPELINE_STAGE_ALL_GPU_COMMANDS = 0x00003FFF,
+} VkPipelineStageFlagBits;
+typedef VkFlags VkPipelineStageFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkMemoryOutputFlags                         outputMask;
+    VkMemoryInputFlags                          inputMask;
+    uint32_t                                    srcQueueFamilyIndex;
+    uint32_t                                    destQueueFamilyIndex;
+    VkBuffer                                    buffer;
+    VkDeviceSize                                offset;
+    VkDeviceSize                                size;
+} VkBufferMemoryBarrier;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkMemoryOutputFlags                         outputMask;
+    VkMemoryInputFlags                          inputMask;
+    VkImageLayout                               oldLayout;
+    VkImageLayout                               newLayout;
+    uint32_t                                    srcQueueFamilyIndex;
+    uint32_t                                    destQueueFamilyIndex;
+    VkImage                                     image;
+    VkImageSubresourceRange                     subresourceRange;
+} VkImageMemoryBarrier;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkMemoryOutputFlags                         outputMask;
+    VkMemoryInputFlags                          inputMask;
+} VkMemoryBarrier;
+
+void VKAPI vkCmdPipelineBarrier(
+    VkCmdBuffer                                 cmdBuffer,
+    VkPipelineStageFlags                        srcStageMask,
+    VkPipelineStageFlags                        destStageMask,
+    VkBool32                                    byRegion,
+    uint32_t                                    memBarrierCount,
+    const void* const*                          ppMemBarriers);
+
+// \note vkCmdWaitEvents includes memory barriers as well
+----
+
+ * Image layout transitions may need special care
+
+Binding memory to objects
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+VkResult VKAPI vkBindBufferMemory(
+    VkDevice                                    device,
+    VkBuffer                                    buffer,
+    VkDeviceMemory                              mem,
+    VkDeviceSize                                memOffset);
+
+VkResult VKAPI vkBindImageMemory(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkDeviceMemory                              mem,
+    VkDeviceSize                                memOffset);
+----
+
+ * Buffers and images only
+ * Straightforward mapping where allocation size matches object size and memOffset = 0
+ * Sub-allocation of larger allocations
+ * Re-binding object to different memory allocation
+ * Binding multiple objects to same or partially overlapping memory ranges
+ ** Aliasing writable resources? Access granularity?
+ * Binding various (supported) types of memory allocations
+
+.Spec issues
+ * When binding multiple objects to same memory, will data in memory be visible for all objects?
+ ** Reinterpretation rules?
+ * Memory contents after re-binding memory to a different object?
+
+Sparse resources
+----------------
+
+Sparse memory resources are treated as separate feature from basic memory management. Details TBD still.
+
+[source,c]
+----
+typedef enum {
+    VK_SPARSE_MEMORY_BIND_REPLICATE_64KIB_BLOCK_BIT = 0x00000001,
+} VkSparseMemoryBindFlagBits;
+typedef VkFlags VkSparseMemoryBindFlags;
+
+typedef struct {
+    VkDeviceSize                                offset;
+    VkDeviceSize                                memOffset;
+    VkDeviceMemory                              mem;
+    VkSparseMemoryBindFlags                     flags;
+} VkSparseMemoryBindInfo;
+
+VkResult VKAPI vkQueueBindSparseBufferMemory(
+    VkQueue                                     queue,
+    VkBuffer                                    buffer,
+    uint32_t                                    numBindings,
+    const VkSparseMemoryBindInfo*               pBindInfo);
+
+VkResult VKAPI vkQueueBindSparseImageOpaqueMemory(
+    VkQueue                                     queue,
+    VkImage                                     image,
+    uint32_t                                    numBindings,
+    const VkSparseMemoryBindInfo*               pBindInfo);
+
+// Non-opaque sparse images
+
+typedef enum {
+    VK_SPARSE_IMAGE_FMT_SINGLE_MIPTAIL_BIT = 0x00000001,
+    VK_SPARSE_IMAGE_FMT_ALIGNED_MIP_SIZE_BIT = 0x00000002,
+    VK_SPARSE_IMAGE_FMT_NONSTD_BLOCK_SIZE_BIT = 0x00000004,
+} VkSparseImageFormatFlagBits;
+typedef VkFlags VkSparseImageFormatFlags;
+
+typedef struct {
+    VkImageAspect                               aspect;
+    VkExtent3D                                  imageGranularity;
+    VkSparseImageFormatFlags                    flags;
+} VkSparseImageFormatProperties;
+
+VkResult VKAPI vkGetPhysicalDeviceSparseImageFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    uint32_t                                    samples,
+    VkImageUsageFlags                           usage,
+    VkImageTiling                               tiling,
+    uint32_t*                                   pNumProperties,
+    VkSparseImageFormatProperties*              pProperties);
+
+typedef struct {
+    VkSparseImageFormatProperties               formatProps;
+    uint32_t                                    imageMipTailStartLOD;
+    VkDeviceSize                                imageMipTailSize;
+    VkDeviceSize                                imageMipTailOffset;
+    VkDeviceSize                                imageMipTailStride;
+} VkSparseImageMemoryRequirements;
+
+VkResult VKAPI vkGetImageSparseMemoryRequirements(
+    VkDevice                                    device,
+    VkImage                                     image,
+    uint32_t*                                   pNumRequirements,
+    VkSparseImageMemoryRequirements*            pSparseMemoryRequirements);
+
+typedef struct {
+    VkImageSubresource                          subresource;
+    VkOffset3D                                  offset;
+    VkExtent3D                                  extent;
+    VkDeviceSize                                memOffset;
+    VkDeviceMemory                              mem;
+    VkSparseMemoryBindFlags                     flags;
+} VkSparseImageMemoryBindInfo;
+
+VkResult VKAPI vkQueueBindSparseImageMemory(
+    VkQueue                                     queue,
+    VkImage                                     image,
+    uint32_t                                    numBindings,
+    const VkSparseImageMemoryBindInfo*          pBindInfo);
+----
+
+Binding model
+-------------
+
+The objective of the binding model tests is to verify:
+
+ * All valid descriptor sets can be created
+ * Accessing resources from shaders using various layouts
+ * Descriptor updates
+ * Descriptor set chaining
+ * Descriptor set limits
+
+As a necessary side effect, the tests will provide coverage for allocating and accessing all types of resources from all shader stages.
+
+Descriptor set functions
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+// DescriptorSetLayout
+
+typedef struct {
+    VkDescriptorType                            descriptorType;
+    uint32_t                                    arraySize;
+    VkShaderStageFlags                          stageFlags;
+    const VkSampler*                            pImmutableSamplers;
+} VkDescriptorSetLayoutBinding;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    count;
+    const VkDescriptorSetLayoutBinding*         pBinding;
+} VkDescriptorSetLayoutCreateInfo;
+
+VkResult VKAPI vkCreateDescriptorSetLayout(
+    VkDevice                                    device,
+    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+    VkDescriptorSetLayout*                      pSetLayout);
+
+// DescriptorPool
+
+typedef struct {
+    VkDescriptorType                            type;
+    uint32_t                                    count;
+} VkDescriptorTypeCount;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    count;
+    const VkDescriptorTypeCount*                pTypeCount;
+} VkDescriptorPoolCreateInfo;
+
+VkResult VKAPI vkCreateDescriptorPool(
+    VkDevice                                    device,
+    VkDescriptorPoolUsage                       poolUsage,
+    uint32_t                                    maxSets,
+    const VkDescriptorPoolCreateInfo*           pCreateInfo,
+    VkDescriptorPool*                           pDescriptorPool);
+
+VkResult VKAPI vkResetDescriptorPool(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool);
+
+// DescriptorSet
+
+typedef struct {
+    VkBufferView                                bufferView;
+    VkSampler                                   sampler;
+    VkImageView                                 imageView;
+    VkAttachmentView                            attachmentView;
+    VkImageLayout                               imageLayout;
+} VkDescriptorInfo;
+
+VkResult VKAPI vkAllocDescriptorSets(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool,
+    VkDescriptorSetUsage                        setUsage,
+    uint32_t                                    count,
+    const VkDescriptorSetLayout*                pSetLayouts,
+    VkDescriptorSet*                            pDescriptorSets,
+    uint32_t*                                   pCount);
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkDescriptorSet                             destSet;
+    uint32_t                                    destBinding;
+    uint32_t                                    destArrayElement;
+    uint32_t                                    count;
+    VkDescriptorType                            descriptorType;
+    const VkDescriptorInfo*                     pDescriptors;
+} VkWriteDescriptorSet;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkDescriptorSet                             srcSet;
+    uint32_t                                    srcBinding;
+    uint32_t                                    srcArrayElement;
+    VkDescriptorSet                             destSet;
+    uint32_t                                    destBinding;
+    uint32_t                                    destArrayElement;
+    uint32_t                                    count;
+} VkCopyDescriptorSet;
+
+VkResult VKAPI vkUpdateDescriptorSets(
+    VkDevice                                    device,
+    uint32_t                                    writeCount,
+    const VkWriteDescriptorSet*                 pDescriptorWrites,
+    uint32_t                                    copyCount,
+    const VkCopyDescriptorSet*                  pDescriptorCopies);
+----
+
+Pipeline layout functions
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pipeline layouts will be covered mostly by tests that use various layouts, but in addition some corner-case tests are needed:
+
+ * Creating empty layouts for shaders that don't use any resources
+ ** For example: vertex data generated with +gl_VertexID+ only
+
+[source,c]
+----
+typedef struct {
+    VkShaderStageFlags                          stageFlags;
+    uint32_t                                    start;
+    uint32_t                                    length;
+} VkPushConstantRange;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    descriptorSetCount;
+    const VkDescriptorSetLayout*                pSetLayouts;
+    uint32_t                                    pushConstantRangeCount;
+    const VkPushConstantRange*                  pPushConstantRanges;
+} VkPipelineLayoutCreateInfo;
+
+VkResult VKAPI vkCreatePipelineLayout(
+    VkDevice                                    device,
+    const VkPipelineLayoutCreateInfo*           pCreateInfo,
+    VkPipelineLayout*                           pPipelineLayout);
+----
+
+Multipass
+---------
+
+Multipass tests will verify:
+
+ * Various possible multipass data flow configurations
+ ** Target formats, number of targets, load, store, resolve, dependencies, ...
+ ** Exhaustive tests for selected dimensions
+ ** Randomized tests
+ * Interaction with other features
+ ** Blending
+ ** Tessellation, geometry shaders (esp. massive geometry expansion)
+ ** Barriers that may cause tiler flushes
+ ** Queries
+ * Large passes that may require tiler flushes
+
+[source,c]
+----
+// Framebuffer
+
+typedef struct {
+    VkAttachmentView                            view;
+    VkImageLayout                               layout;
+} VkAttachmentBindInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkRenderPass                                renderPass;
+    uint32_t                                    attachmentCount;
+    const VkAttachmentBindInfo*                 pAttachments;
+    uint32_t                                    width;
+    uint32_t                                    height;
+    uint32_t                                    layers;
+} VkFramebufferCreateInfo;
+
+VkResult VKAPI vkCreateFramebuffer(
+    VkDevice                                    device,
+    const VkFramebufferCreateInfo*              pCreateInfo,
+    VkFramebuffer*                              pFramebuffer);
+
+// RenderPass
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkFormat                                    format;
+    uint32_t                                    samples;
+    VkAttachmentLoadOp                          loadOp;
+    VkAttachmentStoreOp                         storeOp;
+    VkAttachmentLoadOp                          stencilLoadOp;
+    VkAttachmentStoreOp                         stencilStoreOp;
+    VkImageLayout                               initialLayout;
+    VkImageLayout                               finalLayout;
+} VkAttachmentDescription;
+
+typedef struct {
+    uint32_t                                    attachment;
+    VkImageLayout                               layout;
+} VkAttachmentReference;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkPipelineBindPoint                         pipelineBindPoint;
+    VkSubpassDescriptionFlags                   flags;
+    uint32_t                                    inputCount;
+    const VkAttachmentReference*                inputAttachments;
+    uint32_t                                    colorCount;
+    const VkAttachmentReference*                colorAttachments;
+    const VkAttachmentReference*                resolveAttachments;
+    VkAttachmentReference                       depthStencilAttachment;
+    uint32_t                                    preserveCount;
+    const VkAttachmentReference*                preserveAttachments;
+} VkSubpassDescription;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    srcSubpass;
+    uint32_t                                    destSubpass;
+    VkPipelineStageFlags                        srcStageMask;
+    VkPipelineStageFlags                        destStageMask;
+    VkMemoryOutputFlags                         outputMask;
+    VkMemoryInputFlags                          inputMask;
+    VkBool32                                    byRegion;
+} VkSubpassDependency;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    attachmentCount;
+    const VkAttachmentDescription*              pAttachments;
+    uint32_t                                    subpassCount;
+    const VkSubpassDescription*                 pSubpasses;
+    uint32_t                                    dependencyCount;
+    const VkSubpassDependency*                  pDependencies;
+} VkRenderPassCreateInfo;
+
+VkResult VKAPI vkCreateRenderPass(
+    VkDevice                                    device,
+    const VkRenderPassCreateInfo*               pCreateInfo,
+    VkRenderPass*                               pRenderPass);
+
+VkResult VKAPI vkGetRenderAreaGranularity(
+    VkDevice                                    device,
+    VkRenderPass                                renderPass,
+    VkExtent2D*                                 pGranularity);
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkRenderPass                                renderPass;
+    VkFramebuffer                               framebuffer;
+    VkRect2D                                    renderArea;
+    uint32_t                                    attachmentCount;
+    const VkClearValue*                         pAttachmentClearValues;
+} VkRenderPassBeginInfo;
+
+typedef enum {
+    VK_RENDER_PASS_CONTENTS_INLINE = 0,
+    VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS = 1,
+    VK_RENDER_PASS_CONTENTS_BEGIN_RANGE = VK_RENDER_PASS_CONTENTS_INLINE,
+    VK_RENDER_PASS_CONTENTS_END_RANGE = VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS,
+    VK_RENDER_PASS_CONTENTS_NUM = (VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS - VK_RENDER_PASS_CONTENTS_INLINE + 1),
+    VK_RENDER_PASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
+} VkRenderPassContents;
+
+void VKAPI vkCmdBeginRenderPass(
+    VkCmdBuffer                                 cmdBuffer,
+    const VkRenderPassBeginInfo*                pRenderPassBegin,
+    VkRenderPassContents                        contents);
+
+void VKAPI vkCmdNextSubpass(
+    VkCmdBuffer                                 cmdBuffer,
+    VkRenderPassContents                        contents);
+
+void VKAPI vkCmdEndRenderPass(
+    VkCmdBuffer                                 cmdBuffer);
+----
+
+Device initialization
+---------------------
+
+Device initialization tests verify that all reported devices can be created, with various possible configurations.
+
+[source,c]
+----
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    const char*                                 pAppName;
+    uint32_t                                    appVersion;
+    const char*                                 pEngineName;
+    uint32_t                                    engineVersion;
+    uint32_t                                    apiVersion;
+} VkApplicationInfo;
+
+typedef void* (VKAPI *PFN_vkAllocFunction)(
+    void*                           pUserData,
+    size_t                          size,
+    size_t                          alignment,
+    VkSystemAllocType               allocType);
+
+typedef void (VKAPI *PFN_vkFreeFunction)(
+    void*                           pUserData,
+    void*                           pMem);
+
+typedef struct {
+    void*                                       pUserData;
+    PFN_vkAllocFunction                         pfnAlloc;
+    PFN_vkFreeFunction                          pfnFree;
+} VkAllocCallbacks;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    const VkApplicationInfo*                    pAppInfo;
+    const VkAllocCallbacks*                     pAllocCb;
+    uint32_t                                    layerCount;
+    const char*const*                           ppEnabledLayerNames;
+    uint32_t                                    extensionCount;
+    const char*const*                           ppEnabledExtensionNames;
+} VkInstanceCreateInfo;
+
+VkResult VKAPI vkCreateInstance(
+    const VkInstanceCreateInfo*                 pCreateInfo,
+    VkInstance*                                 pInstance);
+----
+
+ - +VkApplicationInfo+ parameters
+   * Arbitrary +pAppName+ / +pEngineName+ (spaces, utf-8, ...)
+   * +pAppName+ / +pEngineName+ = NULL?
+   * +appVersion+ / +engineVersion+ for 0, ~0, couple of values
+   * Valid +apiVersion+
+   * Invalid +apiVersion+ (expected to fail?)
+ - +VkAllocCallbacks+
+   * Want to be able to run all tests with and without callbacks?
+   ** See discussion about default device in framework section
+   * Custom allocators that provide guardbands and check them at free
+   * Override malloc / free and verify that driver doesn't call if callbacks provided
+   ** As part of object mgmt tests
+   * Must be inherited to all devices created from instance
+ - +VkInstanceCreateInfo+
+   * Empty extension list
+   * Unsupported extensions (expect VK_UNSUPPORTED)
+   * Various combinations of supported extensions
+   ** Any dependencies between extensions (enabling Y requires enabling X)?
+
+.Spec issues
+ * Only VkPhysicalDevice is passed to vkCreateDevice, ICD-specific magic needed for passing callbacks down to VkDevice instance
+
+[source,c]
+----
+typedef struct {
+    VkBool32                                    robustBufferAccess;
+    VkBool32                                    fullDrawIndexUint32;
+    VkBool32                                    imageCubeArray;
+    VkBool32                                    independentBlend;
+    VkBool32                                    geometryShader;
+    VkBool32                                    tessellationShader;
+    VkBool32                                    sampleRateShading;
+    VkBool32                                    dualSourceBlend;
+    VkBool32                                    logicOp;
+    VkBool32                                    instancedDrawIndirect;
+    VkBool32                                    depthClip;
+    VkBool32                                    depthBiasClamp;
+    VkBool32                                    fillModeNonSolid;
+    VkBool32                                    depthBounds;
+    VkBool32                                    wideLines;
+    VkBool32                                    largePoints;
+    VkBool32                                    textureCompressionETC2;
+    VkBool32                                    textureCompressionASTC_LDR;
+    VkBool32                                    textureCompressionBC;
+    VkBool32                                    pipelineStatisticsQuery;
+    VkBool32                                    vertexSideEffects;
+    VkBool32                                    tessellationSideEffects;
+    VkBool32                                    geometrySideEffects;
+    VkBool32                                    fragmentSideEffects;
+    VkBool32                                    shaderTessellationPointSize;
+    VkBool32                                    shaderGeometryPointSize;
+    VkBool32                                    shaderTextureGatherExtended;
+    VkBool32                                    shaderStorageImageExtendedFormats;
+    VkBool32                                    shaderStorageImageMultisample;
+    VkBool32                                    shaderStorageBufferArrayConstantIndexing;
+    VkBool32                                    shaderStorageImageArrayConstantIndexing;
+    VkBool32                                    shaderUniformBufferArrayDynamicIndexing;
+    VkBool32                                    shaderSampledImageArrayDynamicIndexing;
+    VkBool32                                    shaderStorageBufferArrayDynamicIndexing;
+    VkBool32                                    shaderStorageImageArrayDynamicIndexing;
+    VkBool32                                    shaderClipDistance;
+    VkBool32                                    shaderCullDistance;
+    VkBool32                                    shaderFloat64;
+    VkBool32                                    shaderInt64;
+    VkBool32                                    shaderFloat16;
+    VkBool32                                    shaderInt16;
+    VkBool32                                    shaderResourceResidency;
+    VkBool32                                    shaderResourceMinLOD;
+    VkBool32                                    sparse;
+    VkBool32                                    sparseResidencyBuffer;
+    VkBool32                                    sparseResidencyImage2D;
+    VkBool32                                    sparseResidencyImage3D;
+    VkBool32                                    sparseResidency2Samples;
+    VkBool32                                    sparseResidency4Samples;
+    VkBool32                                    sparseResidency8Samples;
+    VkBool32                                    sparseResidency16Samples;
+    VkBool32                                    sparseResidencyStandard2DBlockShape;
+    VkBool32                                    sparseResidencyStandard2DMSBlockShape;
+    VkBool32                                    sparseResidencyStandard3DBlockShape;
+    VkBool32                                    sparseResidencyAlignedMipSize;
+    VkBool32                                    sparseResidencyNonResident;
+    VkBool32                                    sparseResidencyNonResidentStrict;
+    VkBool32                                    sparseResidencyAliased;
+} VkPhysicalDeviceFeatures;
+
+typedef struct {
+    uint32_t                                    queueFamilyIndex;
+    uint32_t                                    queueCount;
+} VkDeviceQueueCreateInfo;
+
+typedef enum {
+    VK_DEVICE_CREATE_VALIDATION_BIT = 0x00000001,
+} VkDeviceCreateFlagBits;
+typedef VkFlags VkDeviceCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    queueRecordCount;
+    const VkDeviceQueueCreateInfo*              pRequestedQueues;
+    uint32_t                                    layerCount;
+    const char*const*                           ppEnabledLayerNames;
+    uint32_t                                    extensionCount;
+    const char*const*                           ppEnabledExtensionNames;
+    const VkPhysicalDeviceFeatures*             pEnabledFeatures;
+    VkDeviceCreateFlags                         flags;
+} VkDeviceCreateInfo;
+
+VkResult VKAPI vkCreateDevice(
+    VkPhysicalDevice                            physicalDevice,
+    const VkDeviceCreateInfo*                   pCreateInfo,
+    VkDevice*                                   pDevice);
+----
+
+ * Creating multiple devices from single physical device
+ * Different queue configurations
+ ** Combinations of supported node indexes
+ ** Use of all queues simultaneously for various operations
+ ** Various queue counts
+ * Various extension combinations
+ * Flags
+ ** Enabling validation (see spec issues)
+ ** VK_DEVICE_CREATE_MULTI_DEVICE_IQ_MATCH_BIT not relevant for Android
+
+.Spec issues
+ * Can same queue node index used multiple times in +pRequestedQueues+ list?
+ * VK_DEVICE_CREATE_VALIDATION_BIT vs. layers
+
+Queue functions
+---------------
+
+Queue functions (one currently) will have a lot of indicental coverage from other tests, so only targeted corner-case tests are needed:
+
+ * +cmdBufferCount+ = 0
+ * Submitting empty VkCmdBuffer
+
+[source,c]
+----
+VkResult VKAPI vkQueueSubmit(
+    VkQueue                                     queue,
+    uint32_t                                    cmdBufferCount,
+    const VkCmdBuffer*                          pCmdBuffers,
+    VkFence                                     fence);
+----
+
+.Spec issues
+ * Can +fence+ be +NULL+ if app doesn't need it?
+
+Synchronization
+---------------
+
+Synchronization tests will verify that all execution ordering primitives provided by the API will function as expected. Testing scheduling and synchronization robustness will require generating non-trivial workloads and possibly randomization to reveal potential issues.
+
+[source,c]
+----
+VkResult VKAPI vkQueueWaitIdle(
+    VkQueue                                     queue);
+
+VkResult VKAPI vkDeviceWaitIdle(
+    VkDevice                                    device);
+----
+
+ * Verify that all sync objects signaled after *WaitIdle() returns
+ ** Fences (vkGetFenceStatus)
+ ** Events (vkEventGetStatus)
+ ** No way to query semaphore status?
+ * Threads blocking at vkWaitForFences() must be resumed
+ * Various amounts of work queued (from nothing to large command buffers)
+ * vkDeviceWaitIdle() concurrently with commands that submit more work
+ * all types of work
+
+Fences
+~~~~~~
+
+[source,c]
+----
+typedef enum {
+    VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001,
+} VkFenceCreateFlagBits;
+typedef VkFlags VkFenceCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkFenceCreateFlags                          flags;
+} VkFenceCreateInfo;
+
+VkResult VKAPI vkCreateFence(
+    VkDevice                                    device,
+    const VkFenceCreateInfo*                    pCreateInfo,
+    VkFence*                                    pFence);
+
+VkResult VKAPI vkResetFences(
+    VkDevice                                    device,
+    uint32_t                                    fenceCount,
+    const VkFence*                              pFences);
+
+VkResult VKAPI vkGetFenceStatus(
+    VkDevice                                    device,
+    VkFence                                     fence);
+
+VkResult VKAPI vkWaitForFences(
+    VkDevice                                    device,
+    uint32_t                                    fenceCount,
+    const VkFence*                              pFences,
+    VkBool32                                    waitAll,
+    uint64_t                                    timeout);
+----
+
+ * Basic waiting on fences
+ ** All types of commands
+ ** Waiting on a different thread than the thread that submitted the work
+ * Reusing fences (vkResetFences)
+ * Waiting on a fence / querying status of a fence before it has been submitted to be signaled
+ * Waiting on a fence / querying status of a fence has just been created with CREATE_SIGNALED_BIT
+ ** Reuse in different queue
+ ** Different queues
+
+.Spec issues
+ * Using same fence in multiple vkQueueSubmit calls without waiting/resetting in between
+ ** Completion of first cmdbuf will reset fence and others won't do anything?
+ * Waiting on same fence from multiple threads?
+
+Semaphores
+~~~~~~~~~~
+
+[source,c]
+----
+typedef VkFlags VkSemaphoreCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkSemaphoreCreateFlags                      flags;
+} VkSemaphoreCreateInfo;
+
+VkResult VKAPI vkCreateSemaphore(
+    VkDevice                                    device,
+    const VkSemaphoreCreateInfo*                pCreateInfo,
+    VkSemaphore*                                pSemaphore);
+
+VkResult VKAPI vkQueueSignalSemaphore(
+    VkQueue                                     queue,
+    VkSemaphore                                 semaphore);
+
+VkResult VKAPI vkQueueWaitSemaphore(
+    VkQueue                                     queue,
+    VkSemaphore                                 semaphore);
+----
+
+ * All types of commands waiting & signaling semaphore
+ * Cross-queue semaphores
+ * Queuing wait on initially signaled semaphore
+ * Queuing wait immediately after queuing signaling
+ * vkQueueWaitIdle & vkDeviceWaitIdle waiting on semaphore
+ * Multiple queues waiting on same semaphore
+
+NOTE: Semaphores might change; counting is causing problems for some IHVs.
+
+Events
+~~~~~~
+
+[source,c]
+----
+typedef VkFlags VkEventCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkEventCreateFlags                          flags;
+} VkEventCreateInfo;
+
+VkResult VKAPI vkCreateEvent(
+    VkDevice                                    device,
+    const VkEventCreateInfo*                    pCreateInfo,
+    VkEvent*                                    pEvent);
+
+VkResult VKAPI vkGetEventStatus(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VkResult VKAPI vkSetEvent(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VkResult VKAPI vkResetEvent(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+void VKAPI vkCmdSetEvent(
+    VkCmdBuffer                                 cmdBuffer,
+    VkEvent                                     event,
+    VkPipelineStageFlags                        stageMask);
+
+void VKAPI vkCmdResetEvent(
+    VkCmdBuffer                                 cmdBuffer,
+    VkEvent                                     event,
+    VkPipelineStageFlags                        stageMask);
+
+void VKAPI vkCmdWaitEvents(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    eventCount,
+    const VkEvent*                              pEvents,
+    VkPipelineStageFlags                        srcStageMask,
+    VkPipelineStageFlags                        destStageMask,
+    uint32_t                                    memBarrierCount,
+    const void* const*                          ppMemBarriers);
+----
+
+ * All types of work waiting on all types of events
+ ** Including signaling from CPU side (vkSetEvent)
+ ** Memory barrier
+ * Polling event status (vkGetEventStatus)
+ * Memory barriers (see also GPU cache control)
+ * Corner-cases:
+ ** Re-setting event before it has been signaled
+ ** Polling status of event concurrently with signaling it or re-setting it from another thread
+ ** Multiple commands (maybe multiple queues as well) setting same event
+ *** Presumably first set will take effect, rest have no effect before event is re-set
+
+Pipeline queries
+----------------
+
+Pipeline query test details TBD. These are of lower priority initially.
+
+NOTE: Currently contains only exact occlusion query as mandatory. Might be problematic for some, and may change?
+
+[source,c]
+----
+typedef enum {
+    VK_QUERY_TYPE_OCCLUSION = 0,
+    VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
+    VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
+    VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_PIPELINE_STATISTICS,
+    VK_QUERY_TYPE_NUM = (VK_QUERY_TYPE_PIPELINE_STATISTICS - VK_QUERY_TYPE_OCCLUSION + 1),
+    VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkQueryType;
+
+typedef enum {
+    VK_QUERY_PIPELINE_STATISTIC_IA_VERTICES_BIT = 0x00000001,
+    VK_QUERY_PIPELINE_STATISTIC_IA_PRIMITIVES_BIT = 0x00000002,
+    VK_QUERY_PIPELINE_STATISTIC_VS_INVOCATIONS_BIT = 0x00000004,
+    VK_QUERY_PIPELINE_STATISTIC_GS_INVOCATIONS_BIT = 0x00000008,
+    VK_QUERY_PIPELINE_STATISTIC_GS_PRIMITIVES_BIT = 0x00000010,
+    VK_QUERY_PIPELINE_STATISTIC_C_INVOCATIONS_BIT = 0x00000020,
+    VK_QUERY_PIPELINE_STATISTIC_C_PRIMITIVES_BIT = 0x00000040,
+    VK_QUERY_PIPELINE_STATISTIC_FS_INVOCATIONS_BIT = 0x00000080,
+    VK_QUERY_PIPELINE_STATISTIC_TCS_PATCHES_BIT = 0x00000100,
+    VK_QUERY_PIPELINE_STATISTIC_TES_INVOCATIONS_BIT = 0x00000200,
+    VK_QUERY_PIPELINE_STATISTIC_CS_INVOCATIONS_BIT = 0x00000400,
+} VkQueryPipelineStatisticFlagBits;
+typedef VkFlags VkQueryPipelineStatisticFlags;
+
+typedef enum {
+    VK_QUERY_RESULT_DEFAULT = 0,
+    VK_QUERY_RESULT_64_BIT = 0x00000001,
+    VK_QUERY_RESULT_WAIT_BIT = 0x00000002,
+    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004,
+    VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008,
+} VkQueryResultFlagBits;
+typedef VkFlags VkQueryResultFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkQueryType                                 queryType;
+    uint32_t                                    slots;
+    VkQueryPipelineStatisticFlags               pipelineStatistics;
+} VkQueryPoolCreateInfo;
+
+VkResult VKAPI vkCreateQueryPool(
+    VkDevice                                    device,
+    const VkQueryPoolCreateInfo*                pCreateInfo,
+    VkQueryPool*                                pQueryPool);
+
+VkResult VKAPI vkGetQueryPoolResults(
+    VkDevice                                    device,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    startQuery,
+    uint32_t                                    queryCount,
+    size_t*                                     pDataSize,
+    void*                                       pData,
+    VkQueryResultFlags                          flags);
+
+void VKAPI vkCmdBeginQuery(
+    VkCmdBuffer                                 cmdBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    slot,
+    VkQueryControlFlags                         flags);
+
+void VKAPI vkCmdEndQuery(
+    VkCmdBuffer                                 cmdBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    slot);
+
+void VKAPI vkCmdResetQueryPool(
+    VkCmdBuffer                                 cmdBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    startQuery,
+    uint32_t                                    queryCount);
+
+void VKAPI vkCmdCopyQueryPoolResults(
+    VkCmdBuffer                                 cmdBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    startQuery,
+    uint32_t                                    queryCount,
+    VkBuffer                                    destBuffer,
+    VkDeviceSize                                destOffset,
+    VkDeviceSize                                destStride,
+    VkQueryResultFlags                          flags);
+----
+
+Buffers
+-------
+
+Buffers will have a lot of coverage from memory management and access tests. Targeted buffer tests need to verify that various corner-cases and more exotic configurations work as expected.
+
+[source,c]
+----
+typedef enum {
+    VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT = 0x00000001,
+    VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT = 0x00000002,
+    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004,
+    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008,
+    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010,
+    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020,
+    VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
+    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
+    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
+} VkBufferUsageFlagBits;
+typedef VkFlags VkBufferUsageFlags;
+
+typedef enum {
+    VK_BUFFER_CREATE_SPARSE_BIT = 0x00000001,
+    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
+    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
+} VkBufferCreateFlagBits;
+typedef VkFlags VkBufferCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkDeviceSize                                size;
+    VkBufferUsageFlags                          usage;
+    VkBufferCreateFlags                         flags;
+    VkSharingMode                               sharingMode;
+    uint32_t                                    queueFamilyCount;
+    const uint32_t*                             pQueueFamilyIndices;
+} VkBufferCreateInfo;
+
+VkResult VKAPI vkCreateBuffer(
+    VkDevice                                    device,
+    const VkBufferCreateInfo*                   pCreateInfo,
+    VkBuffer*                                   pBuffer);
+----
+
+ * All combinations of create and usage flags work
+ ** There are total 511 combinations of usage flags and 7 combinations of create flags
+ * Buffers of various sizes can be created and they report sensible memory requirements
+ ** Test with different sizes:
+ *** 0 Byte
+ *** 1181 Byte
+ *** 15991 Byte
+ *** 16 kByte
+ *** Device limit (maxTexelBufferSize)
+ * Sparse buffers: very large (limit TBD) buffers can be created
+
+[source,c]
+----
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkBuffer                                    buffer;
+    VkFormat                                    format;
+    VkDeviceSize                                offset;
+    VkDeviceSize                                range;
+} VkBufferViewCreateInfo;
+
+VkResult VKAPI vkCreateBufferView(
+    VkDevice                                    device,
+    const VkBufferViewCreateInfo*               pCreateInfo,
+    VkBufferView*                               pView);
+----
+
+ * Buffer views of all (valid) types and formats can be created from all (compatible) buffers
+ ** There are 2 buffer types and 173 different formats.
+ * Various view sizes
+ ** Complete buffer
+ ** Partial buffer
+ * View can be created before and after attaching memory to buffer
+ ** 2 tests for each bufferView
+ * Changing memory binding makes memory contents visible in already created views
+ ** Concurrently changing memory binding and creating views
+
+.Spec issues
+ * Alignment or size requirements for buffer views?
+
+Images
+------
+
+Like buffers, images will have significant coverage from other test groups that focus on various ways to access image data. Additional coverage not provided by those tests will be included in this feature group.
+
+Image functions
+~~~~~~~~~~~~~~~
+
+.Spec issues
+ * +VK_IMAGE_USAGE_GENERAL+?
+
+[source,c]
+----
+typedef enum {
+    VK_IMAGE_TYPE_1D = 0,
+    VK_IMAGE_TYPE_2D = 1,
+    VK_IMAGE_TYPE_3D = 2,
+    VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D,
+    VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D,
+    VK_IMAGE_TYPE_NUM = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1),
+    VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkImageType;
+
+typedef enum {
+    VK_IMAGE_TILING_LINEAR = 0,
+    VK_IMAGE_TILING_OPTIMAL = 1,
+    VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_LINEAR,
+    VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_OPTIMAL,
+    VK_IMAGE_TILING_NUM = (VK_IMAGE_TILING_OPTIMAL - VK_IMAGE_TILING_LINEAR + 1),
+    VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF
+} VkImageTiling;
+
+typedef enum {
+    VK_IMAGE_USAGE_GENERAL = 0,
+    VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT = 0x00000001,
+    VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT = 0x00000002,
+    VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004,
+    VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008,
+    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010,
+    VK_IMAGE_USAGE_DEPTH_STENCIL_BIT = 0x00000020,
+    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040,
+    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080,
+} VkImageUsageFlagBits;
+typedef VkFlags VkImageUsageFlags;
+
+typedef enum {
+    VK_IMAGE_CREATE_SPARSE_BIT = 0x00000001,
+    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
+    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
+    VK_IMAGE_CREATE_INVARIANT_DATA_BIT = 0x00000008,
+    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000010,
+    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000020,
+} VkImageCreateFlagBits;
+typedef VkFlags VkImageCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkImageType                                 imageType;
+    VkFormat                                    format;
+    VkExtent3D                                  extent;
+    uint32_t                                    mipLevels;
+    uint32_t                                    arraySize;
+    uint32_t                                    samples;
+    VkImageTiling                               tiling;
+    VkImageUsageFlags                           usage;
+    VkImageCreateFlags                          flags;
+    VkSharingMode                               sharingMode;
+    uint32_t                                    queueFamilyCount;
+    const uint32_t*                             pQueueFamilyIndices;
+} VkImageCreateInfo;
+
+VkResult VKAPI vkCreateImage(
+    VkDevice                                    device,
+    const VkImageCreateInfo*                    pCreateInfo,
+    VkImage*                                    pImage);
+
+VkResult VKAPI vkGetImageSubresourceLayout(
+    VkDevice                                    device,
+    VkImage                                     image,
+    const VkImageSubresource*                   pSubresource,
+    VkSubresourceLayout*                        pLayout);
+----
+
+ * All valid and supported combinations of image parameters
+ ** Sampling verification with nearest only (other modes will be covered separately)
+ * Various image sizes
+ * Linear-layout images & writing data from CPU
+ * Copying data between identical opaque-layout images on CPU?
+
+Image view functions
+~~~~~~~~~~~~~~~~~~~~
+
+.Spec issues
+ * What are format compatibility rules?
+ * Can color/depth/stencil attachments to write to image which has different format?
+ ** Can I create DS view of RGBA texture and write to only one component by creating VkDepthStencilView for example?
+ * Image view granularity
+ ** All sub-rects allowed? In all use cases (RTs for example)?
+ * Memory access granularity
+ ** Writing concurrently to different areas of same memory backed by same/different image or view
+
+[source,c]
+----
+typedef struct {
+    VkChannelSwizzle                            r;
+    VkChannelSwizzle                            g;
+    VkChannelSwizzle                            b;
+    VkChannelSwizzle                            a;
+} VkChannelMapping;
+
+typedef struct {
+    VkImageAspect                               aspect;
+    uint32_t                                    baseMipLevel;
+    uint32_t                                    mipLevels;
+    uint32_t                                    baseArraySlice;
+    uint32_t                                    arraySize;
+} VkImageSubresourceRange;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkImage                                     image;
+    VkImageViewType                             viewType;
+    VkFormat                                    format;
+    VkChannelMapping                            channels;
+    VkImageSubresourceRange                     subresourceRange;
+} VkImageViewCreateInfo;
+
+VkResult VKAPI vkCreateImageView(
+    VkDevice                                    device,
+    const VkImageViewCreateInfo*                pCreateInfo,
+    VkImageView*                                pView);
+----
+
+ * Image views of all (valid) types and formats can be created from all (compatible) images
+ * Channel swizzles
+ * Depth- and stencil-mode
+ * Different formats
+ * Various view sizes
+ ** Complete image
+ ** Partial image (mip- or array slice)
+ * View can be created before and after attaching memory to image
+ * Changing memory binding makes memory contents visible in already created views
+ ** Concurrently changing memory binding and creating views
+
+[source,c]
+----
+typedef enum {
+    VK_ATTACHMENT_VIEW_CREATE_READ_ONLY_DEPTH_BIT = 0x00000001,
+    VK_ATTACHMENT_VIEW_CREATE_READ_ONLY_STENCIL_BIT = 0x00000002,
+} VkAttachmentViewCreateFlagBits;
+typedef VkFlags VkAttachmentViewCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkImage                                     image;
+    VkFormat                                    format;
+    uint32_t                                    mipLevel;
+    uint32_t                                    baseArraySlice;
+    uint32_t                                    arraySize;
+    VkAttachmentViewCreateFlags                 flags;
+} VkAttachmentViewCreateInfo;
+
+VkResult VKAPI vkCreateAttachmentView(
+    VkDevice                                    device,
+    const VkAttachmentViewCreateInfo*           pCreateInfo,
+    VkAttachmentView*                           pView);
+----
+
+ * Writing to color/depth/stencil attachments in various view configurations
+ ** Multipass tests will contain some coverage for this
+ ** Image layout
+ ** View size
+ ** Image mip- or array sub-range
+ * +msaaResolveImage+
+ ** TODO What is exactly this?
+
+Shaders
+-------
+
+Shader API test will verify that shader loading functions behave as expected. Verifying that various SPIR-V constructs are accepted and executed correctly however is not an objective; that will be covered more extensively by a separate SPIR-V test set.
+
+[source,c]
+----
+typedef VkFlags VkShaderModuleCreateFlags;
+typedef VkFlags VkShaderCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    size_t                                      codeSize;
+    const void*                                 pCode;
+    VkShaderModuleCreateFlags                   flags;
+} VkShaderModuleCreateInfo;
+
+VkResult VKAPI vkCreateShaderModule(
+    VkDevice                                    device,
+    const VkShaderModuleCreateInfo*             pCreateInfo,
+    VkShaderModule*                             pShaderModule);
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkShaderModule                              module;
+    const char*                                 pName;
+    VkShaderCreateFlags                         flags;
+} VkShaderCreateInfo;
+
+VkResult VKAPI vkCreateShader(
+    VkDevice                                    device,
+    const VkShaderCreateInfo*                   pCreateInfo,
+    VkShader*                                   pShader);
+----
+
+Pipelines
+---------
+
+Construction
+~~~~~~~~~~~~
+
+Pipeline tests will create various pipelines and verify that rendering results appear to match (resulting HW pipeline is correct). Fixed-function unit corner-cases nor accuracy is verified. It is not possible to exhaustively test all pipeline configurations so tests have to test some areas in isolation and extend coverage with randomized tests.
+
+[source,c]
+----
+typedef enum {
+    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
+    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
+    VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
+} VkPipelineCreateFlagBits;
+typedef VkFlags VkPipelineCreateFlags;
+
+typedef struct {
+    uint32_t                                    constantId;
+    size_t                                      size;
+    uint32_t                                    offset;
+} VkSpecializationMapEntry;
+
+typedef struct {
+    uint32_t                                    mapEntryCount;
+    const VkSpecializationMapEntry*             pMap;
+    const size_t                                dataSize;
+    const void*                                 pData;
+} VkSpecializationInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkShaderStage                               stage;
+    VkShader                                    shader;
+    const VkSpecializationInfo*                 pSpecializationInfo;
+} VkPipelineShaderStageCreateInfo;
+
+typedef struct {
+    uint32_t                                    binding;
+    uint32_t                                    strideInBytes;
+    VkVertexInputStepRate                       stepRate;
+} VkVertexInputBindingDescription;
+
+typedef struct {
+    uint32_t                                    location;
+    uint32_t                                    binding;
+    VkFormat                                    format;
+    uint32_t                                    offsetInBytes;
+} VkVertexInputAttributeDescription;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    bindingCount;
+    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
+    uint32_t                                    attributeCount;
+    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
+} VkPipelineVertexInputStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkPrimitiveTopology                         topology;
+    VkBool32                                    primitiveRestartEnable;
+} VkPipelineInputAssemblyStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    patchControlPoints;
+} VkPipelineTessellationStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    viewportCount;
+} VkPipelineViewportStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkBool32                                    depthClipEnable;
+    VkBool32                                    rasterizerDiscardEnable;
+    VkFillMode                                  fillMode;
+    VkCullMode                                  cullMode;
+    VkFrontFace                                 frontFace;
+} VkPipelineRasterStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    rasterSamples;
+    VkBool32                                    sampleShadingEnable;
+    float                                       minSampleShading;
+    VkSampleMask                                sampleMask;
+} VkPipelineMultisampleStateCreateInfo;
+
+typedef struct {
+    VkStencilOp                                 stencilFailOp;
+    VkStencilOp                                 stencilPassOp;
+    VkStencilOp                                 stencilDepthFailOp;
+    VkCompareOp                                 stencilCompareOp;
+} VkStencilOpState;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkBool32                                    depthTestEnable;
+    VkBool32                                    depthWriteEnable;
+    VkCompareOp                                 depthCompareOp;
+    VkBool32                                    depthBoundsEnable;
+    VkBool32                                    stencilTestEnable;
+    VkStencilOpState                            front;
+    VkStencilOpState                            back;
+} VkPipelineDepthStencilStateCreateInfo;
+
+typedef struct {
+    VkBool32                                    blendEnable;
+    VkBlend                                     srcBlendColor;
+    VkBlend                                     destBlendColor;
+    VkBlendOp                                   blendOpColor;
+    VkBlend                                     srcBlendAlpha;
+    VkBlend                                     destBlendAlpha;
+    VkBlendOp                                   blendOpAlpha;
+    VkChannelFlags                              channelWriteMask;
+} VkPipelineColorBlendAttachmentState;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkBool32                                    alphaToCoverageEnable;
+    VkBool32                                    logicOpEnable;
+    VkLogicOp                                   logicOp;
+    uint32_t                                    attachmentCount;
+    const VkPipelineColorBlendAttachmentState*  pAttachments;
+} VkPipelineColorBlendStateCreateInfo;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    stageCount;
+    const VkPipelineShaderStageCreateInfo*      pStages;
+    const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+    const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+    const VkPipelineTessellationStateCreateInfo* pTessellationState;
+    const VkPipelineViewportStateCreateInfo*    pViewportState;
+    const VkPipelineRasterStateCreateInfo*      pRasterState;
+    const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+    const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+    const VkPipelineColorBlendStateCreateInfo*  pColorBlendState;
+    VkPipelineCreateFlags                       flags;
+    VkPipelineLayout                            layout;
+    VkRenderPass                                renderPass;
+    uint32_t                                    subpass;
+    VkPipeline                                  basePipelineHandle;
+    int32_t                                     basePipelineIndex;
+} VkGraphicsPipelineCreateInfo;
+
+VkResult VKAPI vkCreateGraphicsPipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    count,
+    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
+    VkPipeline*                                 pPipelines);
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkPipelineShaderStageCreateInfo             cs;
+    VkPipelineCreateFlags                       flags;
+    VkPipelineLayout                            layout;
+    VkPipeline                                  basePipelineHandle;
+    int32_t                                     basePipelineIndex;
+} VkComputePipelineCreateInfo;
+
+VkResult VKAPI vkCreateComputePipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    count,
+    const VkComputePipelineCreateInfo*          pCreateInfos,
+    VkPipeline*                                 pPipelines);
+----
+
+Pipeline caches
+^^^^^^^^^^^^^^^
+
+Extend pipeline tests to cases to use pipeline caches, test that pipelines created from pre-populated cache still produce identical results to pipelines created with empty cache.
+
+Verify that maximum cache size is not exceeded.
+
+[source,c]
+----
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    size_t                                      initialSize;
+    const void*                                 initialData;
+    size_t                                      maxSize;
+} VkPipelineCacheCreateInfo;
+
+VkResult VKAPI vkCreatePipelineCache(
+    VkDevice                                    device,
+    const VkPipelineCacheCreateInfo*            pCreateInfo,
+    VkPipelineCache*                            pPipelineCache);
+
+size_t VKAPI vkGetPipelineCacheSize(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache);
+
+VkResult VKAPI vkGetPipelineCacheData(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    void*                                       pData);
+
+VkResult VKAPI vkMergePipelineCaches(
+    VkDevice                                    device,
+    VkPipelineCache                             destCache,
+    uint32_t                                    srcCacheCount,
+    const VkPipelineCache*                      pSrcCaches);
+----
+
+Pipeline state
+~~~~~~~~~~~~~~
+
+Pipeline tests, as they need to verify rendering results, will provide a lot of coverage for pipeline state manipulation. In addition some corner-case tests are needed:
+
+ * Re-setting pipeline state bits before use
+ * Carrying / manipulating only part of state over draw calls
+ * Submitting command buffers that have only pipeline state manipulation calls (should be no-op)
+
+.Spec issues
+ * Does vkCmdBindPipeline invalidate other state bits?
+
+[source,c]
+----
+void VKAPI vkCmdBindPipeline(
+    VkCmdBuffer                                 cmdBuffer,
+    VkPipelineBindPoint                         pipelineBindPoint,
+    VkPipeline                                  pipeline);
+
+void VKAPI vkCmdBindDescriptorSets(
+    VkCmdBuffer                                 cmdBuffer,
+    VkPipelineBindPoint                         pipelineBindPoint,
+    VkPipelineLayout                            layout,
+    uint32_t                                    firstSet,
+    uint32_t                                    setCount,
+    const VkDescriptorSet*                      pDescriptorSets,
+    uint32_t                                    dynamicOffsetCount,
+    const uint32_t*                             pDynamicOffsets);
+
+void VKAPI vkCmdBindIndexBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    VkIndexType                                 indexType);
+
+void VKAPI vkCmdBindVertexBuffers(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    startBinding,
+    uint32_t                                    bindingCount,
+    const VkBuffer*                             pBuffers,
+    const VkDeviceSize*                         pOffsets);
+----
+
+Samplers
+--------
+
+Sampler tests verify that sampler parameters are mapped to correct HW state. That will be verified by sampling various textures in certain configurations (as listed below). More exhaustive texture filtering verification will be done separately.
+
+ * All valid sampler state configurations
+ * Selected texture formats (RGBA8, FP16, integer textures)
+ * All texture types
+ * Mip-mapping with explicit and implicit LOD
+
+[source,c]
+----
+typedef enum {
+    VK_TEX_FILTER_NEAREST = 0,
+    VK_TEX_FILTER_LINEAR = 1,
+    VK_TEX_FILTER_BEGIN_RANGE = VK_TEX_FILTER_NEAREST,
+    VK_TEX_FILTER_END_RANGE = VK_TEX_FILTER_LINEAR,
+    VK_TEX_FILTER_NUM = (VK_TEX_FILTER_LINEAR - VK_TEX_FILTER_NEAREST + 1),
+    VK_TEX_FILTER_MAX_ENUM = 0x7FFFFFFF
+} VkTexFilter;
+
+typedef enum {
+    VK_TEX_MIPMAP_MODE_BASE = 0,
+    VK_TEX_MIPMAP_MODE_NEAREST = 1,
+    VK_TEX_MIPMAP_MODE_LINEAR = 2,
+    VK_TEX_MIPMAP_MODE_BEGIN_RANGE = VK_TEX_MIPMAP_MODE_BASE,
+    VK_TEX_MIPMAP_MODE_END_RANGE = VK_TEX_MIPMAP_MODE_LINEAR,
+    VK_TEX_MIPMAP_MODE_NUM = (VK_TEX_MIPMAP_MODE_LINEAR - VK_TEX_MIPMAP_MODE_BASE + 1),
+    VK_TEX_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF
+} VkTexMipmapMode;
+
+typedef enum {
+    VK_TEX_ADDRESS_WRAP = 0,
+    VK_TEX_ADDRESS_MIRROR = 1,
+    VK_TEX_ADDRESS_CLAMP = 2,
+    VK_TEX_ADDRESS_MIRROR_ONCE = 3,
+    VK_TEX_ADDRESS_CLAMP_BORDER = 4,
+    VK_TEX_ADDRESS_BEGIN_RANGE = VK_TEX_ADDRESS_WRAP,
+    VK_TEX_ADDRESS_END_RANGE = VK_TEX_ADDRESS_CLAMP_BORDER,
+    VK_TEX_ADDRESS_NUM = (VK_TEX_ADDRESS_CLAMP_BORDER - VK_TEX_ADDRESS_WRAP + 1),
+    VK_TEX_ADDRESS_MAX_ENUM = 0x7FFFFFFF
+} VkTexAddress;
+
+typedef enum {
+    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,
+    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,
+    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,
+    VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3,
+    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,
+    VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5,
+    VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+    VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE,
+    VK_BORDER_COLOR_NUM = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1),
+    VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF
+} VkBorderColor;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkTexFilter                                 magFilter;
+    VkTexFilter                                 minFilter;
+    VkTexMipmapMode                             mipMode;
+    VkTexAddress                                addressU;
+    VkTexAddress                                addressV;
+    VkTexAddress                                addressW;
+    float                                       mipLodBias;
+    float                                       maxAnisotropy;
+    VkBool32                                    compareEnable;
+    VkCompareOp                                 compareOp;
+    float                                       minLod;
+    float                                       maxLod;
+    VkBorderColor                               borderColor;
+} VkSamplerCreateInfo;
+
+VkResult VKAPI vkCreateSampler(
+    VkDevice                                    device,
+    const VkSamplerCreateInfo*                  pCreateInfo,
+    VkSampler*                                  pSampler);
+----
+
+Dynamic state objects
+---------------------
+
+Pipeline tests will include coverage for most dynamic state object usage as some pipeline configurations need corresponding dynamic state objects. In addition there are couple of corner-cases worth exploring separately:
+
+ * Re-setting dynamic state bindings one or more times before first use
+ * Dynamic state object binding persistence over pipeline changes
+ * Large amounts of unique dynamic state objects in a command buffer, pass, or multipass
+
+[source,c]
+----
+// Viewport
+
+typedef struct {
+    float                                       originX;
+    float                                       originY;
+    float                                       width;
+    float                                       height;
+    float                                       minDepth;
+    float                                       maxDepth;
+} VkViewport;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    viewportAndScissorCount;
+    const VkViewport*                           pViewports;
+    const VkRect2D*                             pScissors;
+} VkDynamicViewportStateCreateInfo;
+
+VkResult VKAPI vkCreateDynamicViewportState(
+    VkDevice                                    device,
+    const VkDynamicViewportStateCreateInfo*     pCreateInfo,
+    VkDynamicViewportState*                     pState);
+
+void VKAPI vkCmdBindDynamicViewportState(
+    VkCmdBuffer                                 cmdBuffer,
+    VkDynamicViewportState                      dynamicViewportState);
+
+// Raster
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    float                                       depthBias;
+    float                                       depthBiasClamp;
+    float                                       slopeScaledDepthBias;
+    float                                       lineWidth;
+} VkDynamicRasterStateCreateInfo;
+
+VkResult VKAPI vkCreateDynamicRasterState(
+    VkDevice                                    device,
+    const VkDynamicRasterStateCreateInfo*       pCreateInfo,
+    VkDynamicRasterState*                       pState);
+
+void VKAPI vkCmdBindDynamicRasterState(
+    VkCmdBuffer                                 cmdBuffer,
+    VkDynamicRasterState                        dynamicRasterState);
+
+// Color blend
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    float                                       blendConst[4];
+} VkDynamicColorBlendStateCreateInfo;
+
+VkResult VKAPI vkCreateDynamicColorBlendState(
+    VkDevice                                    device,
+    const VkDynamicColorBlendStateCreateInfo*   pCreateInfo,
+    VkDynamicColorBlendState*                   pState);
+
+void VKAPI vkCmdBindDynamicColorBlendState(
+    VkCmdBuffer                                 cmdBuffer,
+    VkDynamicColorBlendState                    dynamicColorBlendState);
+
+// Depth & stencil
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    float                                       minDepthBounds;
+    float                                       maxDepthBounds;
+    uint32_t                                    stencilReadMask;
+    uint32_t                                    stencilWriteMask;
+    uint32_t                                    stencilFrontRef;
+    uint32_t                                    stencilBackRef;
+} VkDynamicDepthStencilStateCreateInfo;
+
+VkResult VKAPI vkCreateDynamicDepthStencilState(
+    VkDevice                                    device,
+    const VkDynamicDepthStencilStateCreateInfo* pCreateInfo,
+    VkDynamicDepthStencilState*                 pState);
+
+void VKAPI vkCmdBindDynamicDepthStencilState(
+    VkCmdBuffer                                 cmdBuffer,
+    VkDynamicDepthStencilState                  dynamicDepthStencilState);
+----
+
+Command buffers
+---------------
+
+Tests for various rendering features will provide significant coverage for command buffer recording. Additional coverage will be needed for:
+
+ * Re-setting command buffers
+ * Very small (empty) and large command buffers
+ * Various optimize flags combined with various command buffer sizes and contents
+ ** Forcing optimize flags in other tests might be useful for finding cases that may break
+
+[source,c]
+----
+typedef enum {
+    VK_CMD_BUFFER_LEVEL_PRIMARY = 0,
+    VK_CMD_BUFFER_LEVEL_SECONDARY = 1,
+    VK_CMD_BUFFER_LEVEL_BEGIN_RANGE = VK_CMD_BUFFER_LEVEL_PRIMARY,
+    VK_CMD_BUFFER_LEVEL_END_RANGE = VK_CMD_BUFFER_LEVEL_SECONDARY,
+    VK_CMD_BUFFER_LEVEL_NUM = (VK_CMD_BUFFER_LEVEL_SECONDARY - VK_CMD_BUFFER_LEVEL_PRIMARY + 1),
+    VK_CMD_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF
+} VkCmdBufferLevel;
+
+typedef VkFlags VkCmdBufferCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkCmdPool                                   cmdPool;
+    VkCmdBufferLevel                            level;
+    VkCmdBufferCreateFlags                      flags;
+} VkCmdBufferCreateInfo;
+
+VkResult VKAPI vkCreateCommandBuffer(
+    VkDevice                                    device,
+    const VkCmdBufferCreateInfo*                pCreateInfo,
+    VkCmdBuffer*                                pCmdBuffer);
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkCmdBufferOptimizeFlags                    flags;
+    VkRenderPass                                renderPass;
+    VkFramebuffer                               framebuffer;
+} VkCmdBufferBeginInfo;
+
+typedef enum {
+    VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT = 0x00000001,
+    VK_CMD_BUFFER_OPTIMIZE_PIPELINE_SWITCH_BIT = 0x00000002,
+    VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT = 0x00000004,
+    VK_CMD_BUFFER_OPTIMIZE_DESCRIPTOR_SET_SWITCH_BIT = 0x00000008,
+    VK_CMD_BUFFER_OPTIMIZE_NO_SIMULTANEOUS_USE_BIT = 0x00000010,
+} VkCmdBufferOptimizeFlagBits;
+typedef VkFlags VkCmdBufferOptimizeFlags;
+
+VkResult VKAPI vkBeginCommandBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    const VkCmdBufferBeginInfo*                 pBeginInfo);
+
+VkResult VKAPI vkEndCommandBuffer(
+    VkCmdBuffer                                 cmdBuffer);
+
+typedef enum {
+    VK_CMD_BUFFER_RESET_RELEASE_RESOURCES = 0x00000001,
+} VkCmdBufferResetFlagBits;
+typedef VkFlags VkCmdBufferResetFlags;
+
+VkResult VKAPI vkResetCommandBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkCmdBufferResetFlags                       flags);
+----
+
+Command pools
+~~~~~~~~~~~~~
+
+TODO
+
+[source,c]
+----
+typedef enum {
+    VK_CMD_POOL_CREATE_TRANSIENT_BIT = 0x00000001,
+    VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,
+} VkCmdPoolCreateFlagBits;
+typedef VkFlags VkCmdPoolCreateFlags;
+
+typedef struct {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    queueFamilyIndex;
+    VkCmdPoolCreateFlags                        flags;
+} VkCmdPoolCreateInfo;
+
+VkResult VKAPI vkCreateCommandPool(
+    VkDevice                                    device,
+    const VkCmdPoolCreateInfo*                  pCreateInfo,
+    VkCmdPool*                                  pCmdPool);
+
+typedef enum {
+    VK_CMD_POOL_RESET_RELEASE_RESOURCES = 0x00000001,
+} VkCmdPoolResetFlagBits;
+typedef VkFlags VkCmdPoolResetFlags;
+
+VkResult VKAPI vkResetCommandPool(
+    VkDevice                                    device,
+    VkCmdPool                                   cmdPool,
+    VkCmdPoolResetFlags                         flags);
+----
+
+2-level command buffers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+TODO
+
+[source,c]
+----
+void VKAPI vkCmdExecuteCommands(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    cmdBuffersCount,
+    const VkCmdBuffer*                          pCmdBuffers);
+----
+
+Draw commands
+-------------
+
+Draw command tests verify that all draw parameters are respected (including vertex input state) and various draw call sizes work correctly. The tests won't however validate that all side effects of shader invocations happen as intended (covered by feature-specific tests) nor that primitive rasterization is fully correct (will be covered by separate targeted tests).
+
+[source,c]
+----
+void VKAPI vkCmdDraw(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    firstVertex,
+    uint32_t                                    vertexCount,
+    uint32_t                                    firstInstance,
+    uint32_t                                    instanceCount);
+
+void VKAPI vkCmdDrawIndexed(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    firstIndex,
+    uint32_t                                    indexCount,
+    int32_t                                     vertexOffset,
+    uint32_t                                    firstInstance,
+    uint32_t                                    instanceCount);
+
+void VKAPI vkCmdDrawIndirect(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    uint32_t                                    count,
+    uint32_t                                    stride);
+
+void VKAPI vkCmdDrawIndexedIndirect(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    uint32_t                                    count,
+    uint32_t                                    stride);
+----
+
+Compute
+-------
+
+Like draw tests, compute dispatch tests will validate that call parameters have desired effects. In addition compute tests need to verify that various dispatch parameters (number of work groups, invocation IDs) are passed correctly to the shader invocations.
+
+NOTE: Assuming that compute-specific shader features, such as shared memory access, is covered by SPIR-V tests.
+
+[source,c]
+----
+void VKAPI vkCmdDispatch(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    x,
+    uint32_t                                    y,
+    uint32_t                                    z);
+
+void VKAPI vkCmdDispatchIndirect(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset);
+----
+
+Copies and blits
+----------------
+
+Buffer copies
+~~~~~~~~~~~~~
+
+Buffer copy tests need to validate that copies and updates happen as expected for both simple and more complex cases:
+
+ * Whole-buffer, partial copies
+ * Small (1 byte) to very large copies and updates
+ * Copies between objects backed by same memory
+
+NOTE: GPU cache control tests need to verify copy source and destination visibility as well.
+
+.Spec issues
+ * Overlapping copies?
+ ** Simple overlap (same buffer)
+ ** Backed by same memory object
+
+[source,c]
+----
+typedef struct {
+    VkDeviceSize                                srcOffset;
+    VkDeviceSize                                destOffset;
+    VkDeviceSize                                copySize;
+} VkBufferCopy;
+
+void VKAPI vkCmdCopyBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    srcBuffer,
+    VkBuffer                                    destBuffer,
+    uint32_t                                    regionCount,
+    const VkBufferCopy*                         pRegions);
+
+void VKAPI vkCmdUpdateBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    destBuffer,
+    VkDeviceSize                                destOffset,
+    VkDeviceSize                                dataSize,
+    const uint32_t*                             pData);
+
+void VKAPI vkCmdFillBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    destBuffer,
+    VkDeviceSize                                destOffset,
+    VkDeviceSize                                fillSize,
+    uint32_t                                    data);
+----
+
+Image copies
+~~~~~~~~~~~~
+
+.Spec issues
+ * What kind of copies are allowed? Blits?
+ * Copy is simply reinterpretation of data?
+ * Does blit unpack & pack data like in GL?
+ ** sRGB conversions
+
+[source,c]
+----
+typedef struct {
+    VkImageSubresource                          srcSubresource;
+    VkOffset3D                                  srcOffset;
+    VkImageSubresource                          destSubresource;
+    VkOffset3D                                  destOffset;
+    VkExtent3D                                  extent;
+} VkImageCopy;
+
+typedef struct {
+    VkImageSubresource                          srcSubresource;
+    VkOffset3D                                  srcOffset;
+    VkExtent3D                                  srcExtent;
+    VkImageSubresource                          destSubresource;
+    VkOffset3D                                  destOffset;
+    VkExtent3D                                  destExtent;
+} VkImageBlit;
+
+void VKAPI vkCmdCopyImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     destImage,
+    VkImageLayout                               destImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageCopy*                          pRegions);
+
+void VKAPI vkCmdBlitImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     destImage,
+    VkImageLayout                               destImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageBlit*                          pRegions,
+    VkTexFilter                                 filter);
+----
+
+Copies between buffers and images
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef struct {
+    VkDeviceSize                                bufferOffset;
+    uint32_t                                    bufferRowLength;
+    uint32_t                                    bufferImageHeight;
+    VkImageSubresource                          imageSubresource;
+    VkOffset3D                                  imageOffset;
+    VkExtent3D                                  imageExtent;
+} VkBufferImageCopy;
+
+void VKAPI vkCmdCopyBufferToImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkBuffer                                    srcBuffer,
+    VkImage                                     destImage,
+    VkImageLayout                               destImageLayout,
+    uint32_t                                    regionCount,
+    const VkBufferImageCopy*                    pRegions);
+
+void VKAPI vkCmdCopyImageToBuffer(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkBuffer                                    destBuffer,
+    uint32_t                                    regionCount,
+    const VkBufferImageCopy*                    pRegions);
+----
+
+Clearing images
+~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef union {
+    float                                       f32[4];
+    int32_t                                     s32[4];
+    uint32_t                                    u32[4];
+} VkClearColorValue;
+
+typedef struct {
+    float                                       depth;
+    uint32_t                                    stencil;
+} VkClearDepthStencilValue;
+
+typedef union {
+    VkClearColorValue                           color;
+    VkClearDepthStencilValue                    ds;
+} VkClearValue;
+
+void VKAPI vkCmdClearColorImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     image,
+    VkImageLayout                               imageLayout,
+    const VkClearColorValue*                    pColor,
+    uint32_t                                    rangeCount,
+    const VkImageSubresourceRange*              pRanges);
+
+void VKAPI vkCmdClearDepthStencilImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     image,
+    VkImageLayout                               imageLayout,
+    float                                       depth,
+    uint32_t                                    stencil,
+    uint32_t                                    rangeCount,
+    const VkImageSubresourceRange*              pRanges);
+
+void VKAPI vkCmdClearColorAttachment(
+    VkCmdBuffer                                 cmdBuffer,
+    uint32_t                                    colorAttachment,
+    VkImageLayout                               imageLayout,
+    const VkClearColorValue*                    pColor,
+    uint32_t                                    rectCount,
+    const VkRect3D*                             pRects);
+
+void VKAPI vkCmdClearDepthStencilAttachment(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImageAspectFlags                          imageAspectMask,
+    VkImageLayout                               imageLayout,
+    float                                       depth,
+    uint32_t                                    stencil,
+    uint32_t                                    rectCount,
+    const VkRect3D*                             pRects);
+----
+
+Multisample resolve
+~~~~~~~~~~~~~~~~~~~
+
+[source,c]
+----
+typedef struct {
+    VkImageSubresource                          srcSubresource;
+    VkOffset3D                                  srcOffset;
+    VkImageSubresource                          destSubresource;
+    VkOffset3D                                  destOffset;
+    VkExtent3D                                  extent;
+} VkImageResolve;
+
+void VKAPI vkCmdResolveImage(
+    VkCmdBuffer                                 cmdBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     destImage,
+    VkImageLayout                               destImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageResolve*                       pRegions);
+----
+
+Push constants
+--------------
+
+TODO
+
+[source,c]
+----
+void VKAPI vkCmdPushConstants(
+    VkCmdBuffer                                 cmdBuffer,
+    VkPipelineLayout                            layout,
+    VkShaderStageFlags                          stageFlags,
+    uint32_t                                    start,
+    uint32_t                                    length,
+    const void*                                 values);
+----
+
+GPU timestamps
+--------------
+
+[source,c]
+----
+typedef enum {
+    VK_TIMESTAMP_TYPE_TOP = 0,
+    VK_TIMESTAMP_TYPE_BOTTOM = 1,
+    VK_TIMESTAMP_TYPE_BEGIN_RANGE = VK_TIMESTAMP_TYPE_TOP,
+    VK_TIMESTAMP_TYPE_END_RANGE = VK_TIMESTAMP_TYPE_BOTTOM,
+    VK_TIMESTAMP_TYPE_NUM = (VK_TIMESTAMP_TYPE_BOTTOM - VK_TIMESTAMP_TYPE_TOP + 1),
+    VK_TIMESTAMP_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkTimestampType;
+
+void VKAPI vkCmdWriteTimestamp(
+    VkCmdBuffer                                 cmdBuffer,
+    VkTimestampType                             timestampType,
+    VkBuffer                                    destBuffer,
+    VkDeviceSize                                destOffset);
+----
+
+ * All timestamp types
+ * Various commands before and after timestamps
+ * Command buffers that only record timestamps
+ * Sanity check (to the extent possible) for timestamps
+ ** TOP >= BOTTOM
+
+.Spec issues
+ * How many bytes timestamp is? Do we need to support both 32-bit and 64-bit?
+ * destOffset probably needs to be aligned?
+ * TOP vs. BOTTOM not well specified
+
+Validation layer tests
+----------------------
+
+Validation layer tests exercise all relevant invalid API usage patterns and verify that correct return values and error messages are generated. In addition validation tests would try to load invalid SPIR-V binaries and verify that all generic SPIR-V, and Vulkan SPIR-V environment rules are checked.
+
+Android doesn't plan to ship validation layer as part of the system image so validation tests are not required by Android CTS and thus are of very low priority currently.
diff --git a/doc/testspecs/VK/apitests.conf b/doc/testspecs/VK/apitests.conf
new file mode 100644
index 0000000..0b31922
--- /dev/null
+++ b/doc/testspecs/VK/apitests.conf
@@ -0,0 +1,5 @@
+[attributes]

+newline=\n

+

+[replacements]

+\+\/-=&plusmn;

diff --git a/external/fetch_sources.py b/external/fetch_sources.py
index 71204f5..f810b17 100644
--- a/external/fetch_sources.py
+++ b/external/fetch_sources.py
@@ -147,7 +147,7 @@
 
 		pushWorkingDir(fullDstPath)
 		try:
-			execute(["git", "fetch", self.url])
+			execute(["git", "fetch", self.url, "+refs/heads/*:refs/remotes/origin/*"])
 			execute(["git", "checkout", self.revision])
 		finally:
 			popWorkingDir()
@@ -168,6 +168,14 @@
 		"a18233c99e1dc59a256180e6871d9305a42e91b3f98799b3ceb98e87e9ec5e31",
 		"libpng",
 		postExtract = postExtractLibpng),
+	GitRepo(
+		"git@gitlab.khronos.org:spirv/spirv-tools.git",
+		"6e5fc02aef16d8cdc65d39c20166cd2775d2af35",
+		"spirv-tools"),
+	GitRepo(
+		"git@gitlab.khronos.org:GLSL/glslang.git",
+		"500e698906229d81c5ebd44661e770474f590897",
+		"glslang"),
 ]
 
 def parseArgs ():
diff --git a/external/glslang/.gitignore b/external/glslang/.gitignore
new file mode 100644
index 0000000..85de9cf
--- /dev/null
+++ b/external/glslang/.gitignore
@@ -0,0 +1 @@
+src
diff --git a/external/glslang/CMakeLists.txt b/external/glslang/CMakeLists.txt
new file mode 100644
index 0000000..97c344b
--- /dev/null
+++ b/external/glslang/CMakeLists.txt
@@ -0,0 +1,112 @@
+# cmake file for glslang
+
+if (NOT DE_DEFS)
+	message(FATAL_ERROR "Include Defs.cmake")
+endif ()
+
+if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/SPIRV/GlslangToSpv.cpp")
+	set(DEFAULT_GLSLANG_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)
+else ()
+	set(DEFAULT_GLSLANG_SRC_PATH "../glslang")
+endif ()
+
+set(GLSLANG_SRC_PATH ${DEFAULT_GLSLANG_SRC_PATH} CACHE STRING "Path to glslang source tree")
+
+if (IS_ABSOLUTE ${GLSLANG_SRC_PATH})
+	set(GLSLANG_ABS_PATH ${GLSLANG_SRC_PATH})
+else ()
+	set(GLSLANG_ABS_PATH "${CMAKE_SOURCE_DIR}/${GLSLANG_SRC_PATH}")
+endif ()
+
+find_package(BISON)
+
+# \todo [2015-06-24 pyry] Full C++11 support on Android requires using CLang + libc++
+if (NOT BISON_FOUND AND DE_OS_IS_WIN32 AND EXISTS ${GLSLANG_ABS_PATH}/tools/bison.exe)
+	message(STATUS "Using pre-built bison executable")
+	set(BISON_EXECUTABLE ${GLSLANG_ABS_PATH}/tools/bison.exe)
+	set(BISON_FOUND ON)
+endif ()
+
+if (BISON_FOUND AND EXISTS ${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/CodeGen.cpp AND NOT DE_OS_IS_ANDROID)
+	message(STATUS "glslang found; building with DEQP_SUPPORT_GLSLANG")
+
+	include_directories(
+		.
+		${GLSLANG_ABS_PATH}
+		${GLSLANG_ABS_PATH}/glslang
+		${GLSLANG_ABS_PATH}/glslang/Include
+		${GLSLANG_ABS_PATH}/glslang/Public
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent
+		${GLSLANG_ABS_PATH}/glslang/GenericCodeGen
+		${GLSLANG_ABS_PATH}/OGLCompilersDLL
+		${GLSLANG_ABS_PATH}/SPIRV
+		${CMAKE_CURRENT_BINARY_DIR}
+		)
+
+	set(GLSLANG_SRCS
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Constant.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/InfoSink.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Initialize.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/IntermTraverse.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Intermediate.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/ParseHelper.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/PoolAlloc.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/RemoveTree.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Scan.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/ShaderLang.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/SymbolTable.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Versions.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/intermOut.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/limits.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/linkValidate.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/parseConst.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/reflection.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/Pp.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpAtom.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpContext.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpMemory.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpScanner.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
+		${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpTokens.cpp
+		${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/CodeGen.cpp
+		${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/Link.cpp
+		${GLSLANG_ABS_PATH}/OGLCompilersDLL/InitializeDll.cpp
+
+		${GLSLANG_ABS_PATH}/SPIRV/GlslangToSpv.cpp
+		${GLSLANG_ABS_PATH}/SPIRV/SpvBuilder.cpp
+		${GLSLANG_ABS_PATH}/SPIRV/SPVRemapper.cpp
+		${GLSLANG_ABS_PATH}/SPIRV/doc.cpp
+		${GLSLANG_ABS_PATH}/SPIRV/disassemble.cpp
+
+		${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp
+		${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h
+
+		osinclude.h
+		osinclude.cpp
+		)
+
+	set(CMAKE_C_FLAGS	${DE_3RD_PARTY_C_FLAGS})
+	set(CMAKE_CXX_FLAGS	${DE_3RD_PARTY_CXX_FLAGS})
+
+	if (DE_COMPILER_IS_GCC OR DE_COMPILER_IS_CLANG)
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+	endif ()
+
+	add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h
+					   COMMAND ${BISON_EXECUTABLE} --defines=${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h -t MachineIndependent/glslang.y -o ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp
+					   MAIN_DEPENDENCY ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/glslang.y
+					   WORKING_DIRECTORY ${GLSLANG_ABS_PATH}/glslang)
+
+	add_library(glslang STATIC ${GLSLANG_SRCS})
+	target_link_libraries(glslang dethread ${ZLIB_LIBRARY})
+
+	set(GLSLANG_INCLUDE_PATH	${GLSLANG_ABS_PATH}	PARENT_SCOPE)
+	set(GLSLANG_LIBRARY			glslang				PARENT_SCOPE)
+	set(DEQP_HAVE_GLSLANG		ON					PARENT_SCOPE)
+
+else ()
+	message(STATUS "glslang not found; GLSL to SPIR-V compilation not available")
+
+	set(DEQP_HAVE_GLSLANG		OFF					PARENT_SCOPE)
+
+endif ()
diff --git a/external/glslang/osinclude.cpp b/external/glslang/osinclude.cpp
new file mode 100644
index 0000000..9341ec7
--- /dev/null
+++ b/external/glslang/osinclude.cpp
@@ -0,0 +1,96 @@
+/*-------------------------------------------------------------------------
+ * dEQP glslang integration
+ * ------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief glslang OS interface.
+ *//*--------------------------------------------------------------------*/
+
+#include "osinclude.h"
+
+namespace glslang
+{
+
+// Thread-local
+
+OS_TLSIndex OS_AllocTLSIndex (void)
+{
+	return deThreadLocal_create();
+}
+
+bool OS_SetTLSValue (OS_TLSIndex nIndex, void* lpvValue)
+{
+	deThreadLocal_set(nIndex, lpvValue);
+	return true;
+}
+
+bool OS_FreeTLSIndex (OS_TLSIndex nIndex)
+{
+	deThreadLocal_destroy(nIndex);
+	return true;
+}
+
+void* OS_GetTLSValue (OS_TLSIndex nIndex)
+{
+	return deThreadLocal_get(nIndex);
+}
+
+// Global lock - not used
+
+void InitGlobalLock (void)
+{
+}
+
+void GetGlobalLock (void)
+{
+}
+
+void ReleaseGlobalLock (void)
+{
+}
+
+// Threading
+
+DE_STATIC_ASSERT(sizeof(void*) >= sizeof(deThread));
+
+void* OS_CreateThread (TThreadEntrypoint entry)
+{
+	return (void*)(deUintptr)deThread_create(entry, DE_NULL, DE_NULL);
+}
+
+void OS_WaitForAllThreads (void* threads, int numThreads)
+{
+	for (int ndx = 0; ndx < numThreads; ndx++)
+	{
+		const deThread thread = (deThread)(deUintptr)((void**)threads)[ndx];
+		deThread_join(thread);
+		deThread_destroy(thread);
+	}
+}
+
+void OS_Sleep (int milliseconds)
+{
+	deSleep(milliseconds);
+}
+
+void OS_DumpMemoryCounters (void)
+{
+	// Not used
+}
+
+} // glslang
diff --git a/external/glslang/osinclude.h b/external/glslang/osinclude.h
new file mode 100644
index 0000000..7174579
--- /dev/null
+++ b/external/glslang/osinclude.h
@@ -0,0 +1,64 @@
+#ifndef _OSINCLUDE_H
+#define _OSINCLUDE_H
+/*-------------------------------------------------------------------------
+ * dEQP glslang integration
+ * ------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief glslang OS interface.
+ *//*--------------------------------------------------------------------*/
+
+#include "deDefs.hpp"
+#include "deThreadLocal.h"
+#include "deThread.h"
+
+namespace glslang
+{
+
+// Thread-local
+
+typedef deThreadLocal OS_TLSIndex;
+
+#define OS_INVALID_TLS_INDEX	DE_NULL
+
+OS_TLSIndex	OS_AllocTLSIndex		(void);
+bool		OS_SetTLSValue			(OS_TLSIndex nIndex, void* lpvValue);
+bool		OS_FreeTLSIndex			(OS_TLSIndex nIndex);
+
+void*		OS_GetTLSValue			(OS_TLSIndex nIndex);
+
+// Global lock?
+
+void		InitGlobalLock			(void);
+void		GetGlobalLock			(void);
+void		ReleaseGlobalLock		(void);
+
+// Threading
+
+typedef deThreadFunc TThreadEntrypoint;
+
+void*		OS_CreateThread			(TThreadEntrypoint);
+void		OS_WaitForAllThreads	(void* threads, int numThreads);
+
+void		OS_Sleep				(int milliseconds);
+
+void		OS_DumpMemoryCounters	(void);
+
+} // glslang
+
+#endif /* _OSINCLUDE_H */
diff --git a/external/spirv-tools/.gitignore b/external/spirv-tools/.gitignore
new file mode 100644
index 0000000..85de9cf
--- /dev/null
+++ b/external/spirv-tools/.gitignore
@@ -0,0 +1 @@
+src
diff --git a/external/spirv-tools/CMakeLists.txt b/external/spirv-tools/CMakeLists.txt
new file mode 100644
index 0000000..c595552
--- /dev/null
+++ b/external/spirv-tools/CMakeLists.txt
@@ -0,0 +1,31 @@
+# cmake file for spirv-tools
+
+if (NOT DE_DEFS)
+	message(FATAL_ERROR "Include Defs.cmake")
+endif ()
+
+if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/include/libspirv/libspirv.h")
+	set(DEFAULT_SPIRV_TOOLS_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)
+else ()
+	set(DEFAULT_SPIRV_TOOLS_SRC_PATH "../spirv-tools")
+endif ()
+
+set(SPIRV_TOOLS_SRC_PATH ${DEFAULT_SPIRV_TOOLS_SRC_PATH} CACHE STRING "Path to spirv-tools source tree")
+if (IS_ABSOLUTE ${SPIRV_TOOLS_SRC_PATH})
+	set(SPIRV_TOOLS_ABS_PATH ${SPIRV_TOOLS_SRC_PATH})
+else ()
+	set(SPIRV_TOOLS_ABS_PATH "${CMAKE_SOURCE_DIR}/${SPIRV_TOOLS_SRC_PATH}")
+endif ()
+
+if (EXISTS ${SPIRV_TOOLS_ABS_PATH}/source/opcode.cpp)
+	message(STATUS "spirv-tools found; building with DEQP_HAVE_SPIRV_TOOLS")
+	set(CMAKE_C_FLAGS ${DE_3RD_PARTY_C_FLAGS})
+	set(CMAKE_CXX_FLAGS ${DE_3RD_PARTY_CXX_FLAGS})
+
+	set(DEQP_HAVE_SPIRV_TOOLS		ON					PARENT_SCOPE)
+	set(SPIRV_SKIP_EXECUTABLES		ON)
+	add_subdirectory(${SPIRV_TOOLS_ABS_PATH} spirv-tools)
+else ()
+	message(STATUS "spirv-tools not found; SPIR-V assembly not available")
+	set(DEQP_HAVE_SPIRV_TOOLS		OFF					PARENT_SCOPE)
+endif ()
diff --git a/external/vulkancts/LICENSE b/external/vulkancts/LICENSE
new file mode 100644
index 0000000..9f586b7
--- /dev/null
+++ b/external/vulkancts/LICENSE
@@ -0,0 +1,25 @@
+
+Copyright (c) 2015 Google Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice(s) and this permission notice shall be
+included in all copies or substantial portions of the Materials.
+
+The Materials are Confidential Information as defined by the
+Khronos Membership Agreement until designated non-confidential by
+Khronos, at which point this condition clause shall be removed.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/external/vulkancts/README.md b/external/vulkancts/README.md
new file mode 100644
index 0000000..356faf0
--- /dev/null
+++ b/external/vulkancts/README.md
@@ -0,0 +1,116 @@
+Vulkan CTS README
+=================
+
+This document describes how to build and run Vulkan Conformance Test suite.
+
+Vulkan CTS is built on dEQP framework. General dEQP documentation is available
+at http://source.android.com/devices/graphics/testing.html
+
+
+Requirements
+------------
+
+Common:
+ * Git (for checking out sources)
+ * Python 2.7.x (all recent versions in 2.x should work, 3.x is not supported)
+ * CMake 2.8 or newer
+
+Win32:
+ * Visual Studio 2013 (glslang uses several C++11 features)
+
+Linux:
+ * Standard toolchain (make, gcc/clang)
+
+
+Building
+--------
+
+To build dEQP, you need first to download sources for zlib, libpng, glslang,
+and spirv-tools.
+
+To download sources, run:
+
+$ python external/fetch_sources.py
+
+You may need to re-run fetch_sources.py to update to the latest glslang and
+spirv-tools revisions occasionally.
+
+NOTE: glslang integration is not yet available on Android due to a toolchain
+bug, so pre-compiled SPIR-V binaries must be used. See instructions below.
+
+
+Running
+-------
+
+Win32:
+
+> cd builddir/external/vulkancts/modules/vulkan
+> Debug/deqp-vk.exe
+
+Linux:
+
+$ cd builddir/external/vulkancts/modules/vulkan
+$ ./deqp-vk
+
+Android:
+
+Using Cherry is recommended. Alternatively you can follow instructions at
+http://source.android.com/devices/graphics/run-tests.html
+
+
+Pre-compiling SPIR-V binaries
+-----------------------------
+
+For distribution, and platforms that don't support GLSL to SPIR-V compilation,
+SPIR-V binaries must be pre-built with following command:
+
+$ python external/vulkancts/build_spirv_binaries.py
+
+Binaries will be written to external/vulkancts/data/vulkan/prebuilt/.
+
+Test modules (or in case of Android, the APK) must be re-built after building
+SPIR-V programs in order for the binaries to be available.
+
+
+Vulkan platform port
+--------------------
+
+Vulkan support from Platform implementation requires providing
+getVulkanPlatform() method in tcu::Platform class implementation.
+
+See framework/common/tcuPlatform.hpp and examples in
+framework/platform/win32/tcuWin32Platform.cpp and
+framework/platform/android/tcuAndroidPlatform.cpp.
+
+
+Null (dummy) driver
+-------------------
+
+For testing and development purposes it might be useful to be able to run
+tests on dummy Vulkan implementation. One such implementation is provided in
+vkNullDriver.cpp. To use that, implement vk::Platform::createLibrary() with
+vk::createNullDriver().
+
+
+Cherry GUI
+----------
+
+Vulkan test module can be used with Cherry (GUI for test execution and
+analysis). Cherry is available at
+https://android.googlesource.com/platform/external/cherry. Please follow
+instructions in README to get started.
+
+To enable support for Vulkan tests, dEQP-VK module must be added to list of
+test packages.
+
+In cherry/testrunner.go, add following line to testPackageDescriptors list
+(line 608 in NewTestRunner function):
+
+{"dEQP-VK", "deqp-vk", "../external/vulkancts/modules/vulkan", dataDir + "dEQP-VK-cases.xml"},
+
+Before first launch, and every time test hierarchy has been modified, test
+case list must be refreshed by running:
+
+$ python scripts/build_caselists.py path/to/cherry/data
+
+Cherry must be restarted for the case list update to take effect.
diff --git a/external/vulkancts/build_spirv_binaries.py b/external/vulkancts/build_spirv_binaries.py
new file mode 100644
index 0000000..8927f79
--- /dev/null
+++ b/external/vulkancts/build_spirv_binaries.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+
+#-------------------------------------------------------------------------
+# Vulkan CTS
+# ----------
+#
+# Copyright (c) 2015 Google Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and/or associated documentation files (the
+# "Materials"), to deal in the Materials without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Materials, and to
+# permit persons to whom the Materials are furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice(s) and this permission notice shall be
+# included in all copies or substantial portions of the Materials.
+#
+# The Materials are Confidential Information as defined by the
+# Khronos Membership Agreement until designated non-confidential by
+# Khronos, at which point this condition clause shall be removed.
+#
+# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+#
+#-------------------------------------------------------------------------
+
+import os
+import sys
+import string
+import argparse
+import tempfile
+import shutil
+import fnmatch
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+
+from build.common import *
+from build.config import *
+from build.build import *
+
+class Module:
+	def __init__ (self, name, dirName, binName):
+		self.name		= name
+		self.dirName	= dirName
+		self.binName	= binName
+
+VULKAN_MODULE		= Module("dEQP-VK", "../external/vulkancts/modules/vulkan", "deqp-vk")
+DEFAULT_BUILD_DIR	= os.path.join(tempfile.gettempdir(), "spirv-binaries", "{targetName}-{buildType}")
+DEFAULT_TARGET		= "null"
+DEFAULT_DST_DIR		= os.path.join(DEQP_DIR, "external", "vulkancts", "data", "vulkan", "prebuilt")
+
+def getBuildConfig (buildPathPtrn, targetName, buildType):
+	buildPath = buildPathPtrn.format(
+		targetName	= targetName,
+		buildType	= buildType)
+
+	return BuildConfig(buildPath, buildType, ["-DDEQP_TARGET=%s" % targetName])
+
+def cleanDstDir (dstPath):
+	binFiles = [f for f in os.listdir(dstPath) if os.path.isfile(os.path.join(dstPath, f)) and fnmatch.fnmatch(f, "*.spirv")]
+
+	for binFile in binFiles:
+		print "Removing %s" % os.path.join(dstPath, binFile)
+		os.remove(os.path.join(dstPath, binFile))
+
+def execBuildPrograms (buildCfg, generator, module, mode, dstPath):
+	workDir = os.path.join(buildCfg.getBuildDir(), "modules", module.dirName)
+
+	pushWorkingDir(workDir)
+
+	try:
+		binPath = generator.getBinaryPath(buildCfg.getBuildType(), os.path.join(".", "vk-build-programs"))
+		execute([binPath, "--mode", mode, "--dst-path", dstPath])
+	finally:
+		popWorkingDir()
+
+def parseArgs ():
+	parser = argparse.ArgumentParser(description = "Build SPIR-V programs",
+									 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+	parser.add_argument("-b",
+						"--build-dir",
+						dest="buildDir",
+						default=DEFAULT_BUILD_DIR,
+						help="Temporary build directory")
+	parser.add_argument("-t",
+						"--build-type",
+						dest="buildType",
+						default="Debug",
+						help="Build type")
+	parser.add_argument("-c",
+						"--deqp-target",
+						dest="targetName",
+						default=DEFAULT_TARGET,
+						help="dEQP build target")
+	parser.add_argument("--mode",
+						dest="mode",
+						default="build",
+						help="Build mode (build or verify)")
+	parser.add_argument("-d",
+						"--dst-path",
+						dest="dstPath",
+						default=DEFAULT_DST_DIR,
+						help="Destination path")
+	return parser.parse_args()
+
+if __name__ == "__main__":
+	args = parseArgs()
+
+	generator	= ANY_GENERATOR
+	buildCfg	= getBuildConfig(args.buildDir, args.targetName, args.buildType)
+	module		= VULKAN_MODULE
+
+	build(buildCfg, generator, ["vk-build-programs"])
+
+	if args.mode == "build":
+		if os.path.exists(args.dstPath):
+			cleanDstDir(args.dstPath)
+		else:
+			os.makedirs(args.dstPath)
+
+	execBuildPrograms(buildCfg, generator, module, args.mode, args.dstPath)
diff --git a/external/vulkancts/data/vulkan/.gitignore b/external/vulkancts/data/vulkan/.gitignore
new file mode 100644
index 0000000..21ba210
--- /dev/null
+++ b/external/vulkancts/data/vulkan/.gitignore
@@ -0,0 +1 @@
+prebuilt
diff --git a/external/vulkancts/data/vulkan/glsl/es310/arrays.test b/external/vulkancts/data/vulkan/glsl/es310/arrays.test
new file mode 100644
index 0000000..94ca016
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/arrays.test
@@ -0,0 +1,1798 @@
+#X1. Type: 					float[5] 								// An array type with 5 elements
+#X2. Return value:			float[5] func() { ... } 				// Function with a 5-element array return value
+#X3. Array constructor:		float[3] (1.0, 2.0, 5.5)				// 3-element array with given elements
+#																	// Fails with array of matrices!
+#X4. As unnamed parameter:	void func(float[5]);
+#X5. Variable declaration:	float[5] a;								// Equivalent to float a[5]; (?)
+#X6. Empty brackets:		float x[] = float[] (1.0, 2.0, 3.0);	// Size of x is 3
+#							float y[] = float[3] (1.0, 2.0, 3.0);	// Size of y is 3 (equivalent)
+#							float z[] = y;							// Size of z is 3
+#X7. Testing that 2-dimensional arrays don't work:	float a[5][3];	// Illegal
+#													float[5] a[3]; 	// Illegal
+#X8. Testing that array declaration with dynamic variables as array size won't work.
+#X9. Testing length() operator:	z.length(); 						// Returns 3 for z defined before
+#X10. Test C/C++ style {}-constructor
+#X11. Test struct arrays
+#X12. Test array element access at initialization with const/dynamic values
+
+group constructor "Array constructors"
+
+	case float3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(7.4, -1.0, 2.0) | vec3(3.0, 1.6, -2.0) ];
+			output vec3 out0 = [ vec3(2.0, 0.5, 1.0) | vec3(2.0, 7.4, -1.0) | vec3(-2.0, 3.0, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				float[3] x;
+				x = float[3] (in0.z, in0.x, in0.y);
+				out0 = vec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.5, 1.0, 2.0, 0.2) | vec4(7.4, -1.0, 2.0, -1.3) | vec4(3.0, 1.6, -2.0, 0.5) ];
+			output vec4 out0 = [ vec4(2.0, 0.5, 0.2, 1.0) | vec4(2.0, 7.4, -1.3, -1.0) | vec4(-2.0, 3.0, 0.5, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				float[4] x;
+				x = float[4] (in0.z, in0.x, in0.w, in0.y);
+				out0 = vec4(x[0], x[1], x[2], x[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 1, 2) | ivec3(7, -1, 2) | ivec3(3, 1, -2) ];
+			output ivec3 out0 = [ ivec3(2, 0, 1) | ivec3(2, 7, -1) | ivec3(-2, 3, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				int[3] x;
+				x = int[3] (in0.z, in0.x, in0.y);
+				out0 = ivec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 1, 2, 0) | ivec4(7, -1, 2, -1) | ivec4(3, 1, -2, 0) ];
+			output ivec4 out0 = [ ivec4(2, 0, 0, 1) | ivec4(2, 7, -1, -1) | ivec4(-2, 3, 0, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				int[4] x;
+				x = int[4] (in0.z, in0.x, in0.w, in0.y);
+				out0 = ivec4(x[0], x[1], x[2], x[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, true, false) ];
+			output bvec3 out0 = [ bvec3(false, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				bool[3] x;
+				x = bool[3] (in0.z, in0.x, in0.y);
+				out0 = bvec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, true, false, false) ];
+			output bvec4 out0 = [ bvec4(false, true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				bool[4] x;
+				x = bool[4] (in0.z, in0.x, in0.y, in0.w);
+				out0 = bvec4(x[0], x[1], x[2], x[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(2.0, -0.5, -1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+
+
+			void main()
+			{
+				${SETUP}
+
+				struct test
+				{
+					float f;
+					vec3 v;
+				};
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+
+				test[3] x = test[3] (a, b, c);
+
+				out0 = vec3(x[0].f, x[1].v.y, x[2].v.x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.5, 1.0, 2.0, 1.5) ];
+			output vec4 out0 = [ vec4(2.0, -0.5, -1.0, -1.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+
+			void main()
+			{
+				${SETUP}
+
+
+				struct test
+				{
+					float f;
+					vec3 v;
+				};
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+				test d = test(-in0.w, vec3(-in0.w, -in0.x, -in0.z));
+
+				test[4] x = test[4] (a, b, c, d);
+
+				out0 = vec4(x[0].f, x[1].v.y, x[2].v.x, x[3].v.x);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case float_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(7.4, -1.0, 2.0) | vec3(3.0, 1.6, -2.0) ];
+			output vec3 out0 = [ vec3(0.5, -2.0, 1.0) | vec3(7.4, -2.0, -1.0) | vec3(3.0, 2.0, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+
+				vec3[3] x;
+				x = vec3[3] ( 	vec3(in0.x, in0.y, in0.z)	,
+								vec3(-in0.y, -in0.z, -in0.x),
+								vec3(in0.z, in0.x, in0.y)	);
+				out0 = vec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_vec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(5, 1, 2) | ivec3(7, -1, 2) | ivec3(3, 1, -2) ];
+			output ivec3 out0 = [ ivec3(5, -2, 1) | ivec3(7, -2, -1) | ivec3(3, 2, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+
+				ivec3[3] x;
+				x = ivec3[3] ( 	ivec3(in0.x, in0.y, in0.z)	,
+								ivec3(-in0.y, -in0.z, -in0.x),
+								ivec3(in0.z, in0.x, in0.y)	);
+				out0 = ivec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_vec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) ];
+			output bvec3 out0 = [ bvec3(true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+
+				bvec3[3] x;
+				x = bvec3[3] ( 	bvec3(in0.x, in0.y, in0.z)	,
+								bvec3(in0.y, in0.z, in0.x),
+								bvec3(in0.z, in0.x, in0.y)	);
+				out0 = bvec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_mat3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(-1.5, 0.0, -2.3) ];
+			output vec3 out0 = [ vec3(0.5, -1.0, 1.0) | vec3(-1.5, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a = mat3[3] (	mat3(	in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z)	,
+										mat3(	in0.z, in0.x, -in0.y,
+												in0.z, in0.x, -in0.y,
+												in0.z, in0.x, -in0.y)	,
+										mat3(	-in0.z, -in0.z, in0.z,
+												-in0.y, -in0.y, in0.y,
+												-in0.x, -in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = vec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_mat3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 1, 2) | ivec3(-1, 0, -2) ];
+			output ivec3 out0 = [ ivec3(0, -1, 1) | ivec3(-1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a = mat3[3] (	mat3(	in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z)	,
+										mat3(	in0.z, in0.x, -in0.y,
+												in0.z, in0.x, -in0.y,
+												in0.z, in0.x, -in0.y)	,
+										mat3(	-in0.z, -in0.z, in0.z,
+												-in0.y, -in0.y, in0.y,
+												-in0.x, -in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = ivec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_mat3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) ];
+			output bvec3 out0 = [ bvec3(true, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a = mat3[3] (	mat3(	in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z,
+												in0.x, in0.y, in0.z)	,
+										mat3(	in0.z, in0.x, in0.y,
+												in0.z, in0.x, in0.y,
+												in0.z, in0.x, in0.y)	,
+										mat3(	in0.z, in0.z, in0.z,
+												in0.y, in0.y, in0.y,
+												in0.x, in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = bvec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # type
+
+group return "Arrays as return value"
+
+	case float
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) | vec3(7.4, -1.0, 2.0) | vec3(3.0, 1.6, -2.0) ];
+			output vec3 out0 = [ vec3(2.0, -0.5, 1.0) | vec3(2.0, -7.4, -1.0) | vec3(-2.0, -3.0, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float[3] func(vec3 a)
+			{
+				return float[3] (a.z, -a.x, a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				float[3] x = func(in0);
+				out0 = vec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(4, 1, 2) | ivec3(7, -1, 2) | ivec3(3, 1, -2) ];
+			output ivec3 out0 =	[ ivec3(2, -4, 1) | ivec3(2, -7, -1) | ivec3(-2, -3, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			int[3] func(ivec3 a)
+			{
+				return int[3] (a.z, -a.x, a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				int[3] x = func(in0);
+				out0 = ivec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool
+		version 310 es
+		values
+		{
+			input bvec3 in0 = 	[ bvec3(false, true, true) ];
+			output bvec3 out0 = [ bvec3(true, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool[3] func(bvec3 a)
+			{
+				return bool[3] (a.z, a.x, a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool[3] x = func(in0);
+				out0 = bvec3(x[0], x[1], x[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+
+	case float_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) | vec3(-0.5, 11.2, -1.0) ];
+			output vec3 out0 = [ vec3(1.0, 0.5, -2.0) | vec3(11.2, -0.5, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec3[3] func(vec3[3] a)
+			{
+				return vec3[3] (a[1], a[2], a[0]);
+			}
+
+			void main()
+			{
+				${SETUP}
+				vec3[3] x = vec3[3](vec3(in0.x, in0.y, -in0.z)	,
+									vec3(in0.y, -in0.z, in0.x)	,
+									vec3(-in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = vec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(-1.0, 2.0, 0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct test
+			{
+				float f;
+				vec3 v;
+			};
+
+			test[3] func(test[3] a)
+			{
+				return test[3] (a[1], a[2], a[0]);
+			}
+
+			void main()
+			{
+				${SETUP}
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+
+				test[3] t = test[3] (a, b, c);
+				test[3] x = func(t);
+
+				out0 = vec3(x[0].v.z, x[1].v.y, x[2].v.x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_vec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = 	[ ivec3(5, 1, 2) | ivec3(-5, 11, -1) ];
+			output ivec3 out0 = [ ivec3(1, 5, -2) | ivec3(11, -5, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			ivec3[3] func(ivec3[3] a)
+			{
+				return ivec3[3] (a[1], a[2], a[0]);
+			}
+
+			void main()
+			{
+				${SETUP}
+				ivec3[3] x = ivec3[3](	ivec3(in0.x, in0.y, -in0.z)	,
+										ivec3(in0.y, -in0.z, in0.x)	,
+										ivec3(-in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = ivec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_vec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = 	[ bvec3(true, false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			bvec3[3] func(bvec3[3] a)
+			{
+				return bvec3[3] (a[1], a[2], a[0]);
+			}
+
+			void main()
+			{
+				${SETUP}
+				bvec3[3] x = bvec3[3](	bvec3(in0.x, in0.y, in0.z)	,
+										bvec3(in0.y, in0.z, in0.x)	,
+										bvec3(in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = bvec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_mat3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(-1.5, 0.0, -2.3) ];
+			output vec3 out0 = [ vec3(2.0, -1.0, 2.0) | vec3(-2.3, 0.0, -2.3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y);
+				a[2] = mat3(-in0.z, -in0.z, in0.z,
+							-in0.y, -in0.y, in0.y,
+							-in0.x, -in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = vec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_mat3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(5, 1, 2) | ivec3(-1, 0, -2) ];
+			output ivec3 out0 = [ ivec3(2, -1, 2) | ivec3(-2, 0, -2) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y);
+				a[2] = mat3(-in0.z, -in0.z, in0.z,
+							-in0.y, -in0.y, in0.y,
+							-in0.x, -in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = ivec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_mat3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) | bvec3(true, true, false) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, in0.y,
+							in0.z, in0.x, in0.y,
+							in0.z, in0.x, in0.y);
+				a[2] = mat3(in0.z, in0.z, in0.z,
+							in0.y, in0.y, in0.y,
+							in0.x, in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = bvec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # return
+
+group unnamed_parameter "Array type as unnamed parameter of a function prototype"
+
+	case float
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) | vec3(7.4, -1.0, 2.0) | vec3(3.0, 1.6, -2.0) ];
+			output vec3 out0 = [ vec3(2.0, 0.5, 1.0) | vec3(2.0, 7.4, -1.0) | vec3(-2.0, 3.0, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float[3] func(float[3]);
+
+			void main()
+			{
+				${SETUP}
+				float[3] a = float[3] (in0.x, in0.y, in0.z);
+				float[3] b = func(a);
+				out0 = vec3(b[0], b[1], b[2]);
+				${OUTPUT}
+			}
+
+			float[3] func(float[3] a)
+			{
+				return float[3] (a[2], a[0], a[1]);
+			}
+
+		""
+	end
+
+	case int
+		version 310 es
+		values
+		{
+			input ivec3 in0 = 	[ ivec3(0, 1, 2) | ivec3(7, -1, 2) | ivec3(3, 1, -2) ];
+			output ivec3 out0 = [ ivec3(2, 0, 1) | ivec3(2, 7, -1) | ivec3(-2, 3, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			int[3] func(int[3]);
+
+			void main()
+			{
+				${SETUP}
+				int[3] a = int[3] (in0.x, in0.y, in0.z);
+				int[3] b = func(a);
+				out0 = ivec3(b[0], b[1], b[2]);
+				${OUTPUT}
+			}
+
+			int[3] func(int[3] a)
+			{
+				return int[3] (a[2], a[0], a[1]);
+			}
+
+		""
+	end
+
+	case bool
+		version 310 es
+		values
+		{
+			input bvec3 in0 = 	[ bvec3(false, true, true) ];
+			output bvec3 out0 = [ bvec3(true, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool[3] func(bool[3]);
+
+			void main()
+			{
+				${SETUP}
+				bool[3] a = bool[3] (in0.x, in0.y, in0.z);
+				bool[3] b = func(a);
+				out0 = bvec3(b[0], b[1], b[2]);
+				${OUTPUT}
+			}
+
+			bool[3] func(bool[3] a)
+			{
+				return bool[3] (a[2], a[0], a[1]);
+			}
+
+		""
+	end
+
+	case struct
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(-1.0, 2.0, 0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct test
+			{
+				float f;
+				vec3 v;
+			};
+
+			test[3] func(test[3]);
+
+			void main()
+			{
+				${SETUP}
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+
+				test[3] t = test[3] (a, b, c);
+				test[3] x = func(t);
+				out0 = vec3(x[0].v.z, x[1].v.y, x[2].v.x);
+				${OUTPUT}
+			}
+
+			test[3] func(test[3] a)
+			{
+				return test[3] (a[1], a[2], a[0]);
+			}
+
+		""
+	end
+
+	case float_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) | vec3(-0.5, 11.2, -1.0) ];
+			output vec3 out0 = [ vec3(1.0, 0.5, -2.0) | vec3(11.2, -0.5, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec3[3] func(vec3[3]);
+
+			void main()
+			{
+				${SETUP}
+				vec3[3] x = vec3[3](vec3(in0.x, in0.y, -in0.z)	,
+									vec3(in0.y, -in0.z, in0.x)	,
+									vec3(-in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = vec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+
+			vec3[3] func(vec3[3] a)
+			{
+				return vec3[3] (a[1], a[2], a[0]);
+			}
+		""
+	end
+
+	case int_vec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = 	[ ivec3(5, 1, 2) | ivec3(-5, 11, -1) ];
+			output ivec3 out0 = [ ivec3(1, 5, -2) | ivec3(11, -5, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			ivec3[3] func(ivec3[3]);
+
+			void main()
+			{
+				${SETUP}
+				ivec3[3] x = ivec3[3](	ivec3(in0.x, in0.y, -in0.z)	,
+										ivec3(in0.y, -in0.z, in0.x)	,
+										ivec3(-in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = ivec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+
+			ivec3[3] func(ivec3[3] a)
+			{
+				return ivec3[3] (a[1], a[2], a[0]);
+			}
+		""
+	end
+
+	case bool_vec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = 	[ bvec3(true, false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			bvec3[3] func(bvec3[3]);
+
+			void main()
+			{
+				${SETUP}
+				bvec3[3] x = bvec3[3](	bvec3(in0.x, in0.y, in0.z)	,
+										bvec3(in0.y, in0.z, in0.x)	,
+										bvec3(in0.z, in0.x, in0.y)	);
+				x = func(x);
+				out0 = bvec3(x[0].x, x[1].y, x[2].z);
+				${OUTPUT}
+			}
+
+			bvec3[3] func(bvec3[3] a)
+			{
+				return bvec3[3] (a[1], a[2], a[0]);
+			}
+
+		""
+	end
+
+	case float_mat3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(-1.5, 0.0, -2.3) ];
+			output vec3 out0 = [ vec3(2.0, -1.0, 2.0) | vec3(-2.3, 0.0, -2.3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3]);
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y);
+				a[2] = mat3(-in0.z, -in0.z, in0.z,
+							-in0.y, -in0.y, in0.y,
+							-in0.x, -in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = vec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+		""
+	end
+
+	case int_mat3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(5, 1, 2) | ivec3(-1, 0, -2) ];
+			output ivec3 out0 = [ ivec3(2, -1, 2) | ivec3(-2, 0, -2) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3]);
+
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y,
+							in0.z, in0.x, -in0.y);
+				a[2] = mat3(-in0.z, -in0.z, in0.z,
+							-in0.y, -in0.y, in0.y,
+							-in0.x, -in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = ivec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+		""
+	end
+
+	case bool_mat3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) | bvec3(true, true, false) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3[3] func(mat3[3]);
+			void main()
+			{
+				${SETUP}
+				mat3[3] a, b;
+				a[0] = mat3(in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z,
+							in0.x, in0.y, in0.z);
+				a[1] = mat3(in0.z, in0.x, in0.y,
+							in0.z, in0.x, in0.y,
+							in0.z, in0.x, in0.y);
+				a[2] = mat3(in0.z, in0.z, in0.z,
+							in0.y, in0.y, in0.y,
+							in0.x, in0.x, in0.x);
+
+				b = func(a);
+
+				mat3 b0 = b[0];
+				mat3 b1 = b[1];
+				mat3 b2 = b[2];
+
+				float ret0 = b0[0][0];
+				float ret1 = b1[1][1];
+				float ret2 = b2[2][2];
+
+				out0 = bvec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+
+			mat3[3] func(mat3[3] x)
+			{
+				mat3[3] r;
+				r[0] = x[1];
+				r[1] = x[2];
+				r[2] = x[0];
+				return r;
+			}
+		""
+	end
+
+end # unnamed_parameter
+
+group declaration "Declaring arrays"
+
+	case implicit_size_float
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(7.4, -1.0, 2.0) | vec3(3.0, 1.6, -2.0) ];
+			output vec3 out0 = [ vec3(2.0, 0.5, 1.0) | vec3(2.0, 7.4, -1.0) | vec3(-2.0, 3.0, 1.6) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				float[] x = float[] (in0.z, in0.x, in0.y);
+				float[] y = x;
+
+				out0 = vec3(y[0], y[1], y[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_int
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 1, 2) | ivec3(7, -1, 2) | ivec3(3, 1, -2) ];
+			output ivec3 out0 = [ ivec3(2, 0, 1) | ivec3(2, 7, -1) | ivec3(-2, 3, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				int[] x = int[] (in0.z, in0.x, in0.y);
+				int[] y = x;
+
+				out0 = ivec3(y[0], y[1], y[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_bool
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(false, true, true) ];
+			output bvec3 out0 = [ bvec3(true, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				bool[] x = bool[] (in0.z, in0.x, in0.y);
+				bool[] y = x;
+
+				out0 = bvec3(y[0], y[1], y[2]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_struct
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(-1.0, -0.5, 2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct test
+			{
+				float f;
+				vec3 v;
+			};
+
+			void main()
+			{
+				${SETUP}
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+
+				test[] x = test[] (c, b, a);
+				test[] y = x;
+
+				out0 = vec3(y[0].v.x, y[1].v.y, y[2].v.z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_float_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = 	[ vec3(0.5, 1.0, 2.0) | vec3(-0.5, 11.2, -1.0) ];
+			output vec3 out0 = [ vec3(0.5, -2.0, 1.0) | vec3(-0.5, 1.0, 11.2) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				vec3[] x = vec3[] (	vec3(in0.x, in0.y, -in0.z)	,
+									vec3(in0.y, -in0.z, in0.x)	,
+									vec3(-in0.z, in0.x, in0.y)	);
+				vec3[] y = x;
+				out0 = vec3(y[0].x, y[1].y, y[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_int_ivec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = 	[ ivec3(0, 1, 2) | ivec3(5, 11, -1) ];
+			output ivec3 out0 = [ ivec3(0, -2, 1) | ivec3(5, 1, 11) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				ivec3[] x = ivec3[] (	ivec3(in0.x, in0.y, -in0.z)	,
+										ivec3(in0.y, -in0.z, in0.x)	,
+										ivec3(-in0.z, in0.x, in0.y)	);
+				ivec3[] y = x;
+				out0 = ivec3(y[0].x, y[1].y, y[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_bool_bvec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = 	[ bvec3(true, false, true) ];
+			output bvec3 out0 = [ bvec3(true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				bvec3[] x = bvec3[] (	bvec3(in0.x, in0.y, in0.z)	,
+										bvec3(in0.y, in0.z, in0.x)	,
+										bvec3(in0.z, in0.x, in0.y)	);
+				bvec3[] y = x;
+				out0 = bvec3(y[0].x, y[1].y, y[2].z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_float_mat3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) | vec3(-1.5, 0.0, -2.3) ];
+			output vec3 out0 = [ vec3(0.5, -1.0, 1.0) | vec3(-1.5, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[] a = mat3[] (	mat3(	in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z)	,
+									mat3(	in0.z, in0.x, -in0.y,
+											in0.z, in0.x, -in0.y,
+											in0.z, in0.x, -in0.y)	,
+									mat3(	-in0.z, -in0.z, in0.z,
+											-in0.y, -in0.y, in0.y,
+											-in0.x, -in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = vec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_int_mat3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 1, 2) | ivec3(-1, 0, -2) ];
+			output ivec3 out0 = [ ivec3(0, -1, 1) | ivec3(-1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[] a = mat3[] (	mat3(	in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z)	,
+									mat3(	in0.z, in0.x, -in0.y,
+											in0.z, in0.x, -in0.y,
+											in0.z, in0.x, -in0.y)	,
+									mat3(	-in0.z, -in0.z, in0.z,
+											-in0.y, -in0.y, in0.y,
+											-in0.x, -in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = ivec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case implicit_size_bool_mat3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) ];
+			output bvec3 out0 = [ bvec3(true, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				mat3[] a = mat3[] (	mat3(	in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z,
+											in0.x, in0.y, in0.z)	,
+									mat3(	in0.z, in0.x, in0.y,
+											in0.z, in0.x, in0.y,
+											in0.z, in0.x, in0.y)	,
+									mat3(	in0.z, in0.z, in0.z,
+											in0.y, in0.y, in0.y,
+											in0.x, in0.x, in0.x)	);
+
+				mat3 a0 = a[0];
+				mat3 a1 = a[1];
+				mat3 a2 = a[2];
+
+				float ret0 = a0[2][0];
+				float ret1 = a1[0][2];
+				float ret2 = a2[1][2];
+
+				out0 = bvec3(ret0, ret1, ret2);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case constant_expression_array_size
+		version 310 es
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			const int a = 4;
+
+			void main ()
+			{
+				const int b = 5;
+				float[a] array1;
+				float[b] array2;
+				float[array1.length()] array3;
+				float[a+b] array4;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case constant_expression_array_access
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(-2.0, -1.0, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			const int a = 3;
+
+			void main ()
+			{
+				${SETUP}
+				const int b = 2;
+				float x = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [a];
+				float y = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [b+2];
+				float z = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [5];
+				out0 = vec3(x, y, z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case dynamic_expression_array_access
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			input ivec2 in1 = ivec2(3, 2);
+			output vec3 out0 = [ vec3(-2.0, -1.0, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main ()
+			{
+				${SETUP}
+				float x = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [in1.x];
+				float y = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [in1.y+2];
+				float z = float[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x) [in1.x+in1.y];
+				out0 = vec3(x, y, z);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case multiple_declarations_single_statement_explicit
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output vec3 out0 = [ vec3(2.0, -1.0, 0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main ()
+			{
+				${SETUP}
+				float[] x = float[6] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x),
+						y = float[2] (in0.x, -in0.y);
+				out0 = vec3(x[2], y[1], x[0]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case multiple_declarations_single_statement_implicit
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(5, 1, 2) ];
+			output ivec3 out0 = [ ivec3(2, -1, 5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main ()
+			{
+				${SETUP}
+				int[] x = int[] (in0.x, in0.y, in0.z, -in0.z, -in0.y, -in0.x),
+					  y = int[] (in0.x, -in0.y);
+				out0 = ivec3(x[2], y[1], x[0]);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # declaration
+
+group length "Array length method"
+
+	case float
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output ivec3 out0 = [ ivec3(3, 5, 13) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				float[] x = float[3] (in0.z, in0.x, in0.y);
+				float[] y = float[] (in0.z, in0.x, in0.y, in0.x, in0.y);
+				float[13] z;
+
+				out0 = ivec3(x.length(), y.length(), z.length());
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 1, 2) ];
+			output ivec3 out0 = [ ivec3(3, 5, 13) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump int;
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				int[] x = int[3] (in0.z, in0.x, in0.y);
+				int[] y = int[] (in0.z, in0.x, in0.y, in0.x, in0.y);
+				int[13] z;
+
+				out0 = ivec3(x.length(), y.length(), z.length());
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, true) ];
+			output ivec3 out0 = [ ivec3(3, 5, 13) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				bool[] x = bool[3] (in0.z, in0.x, in0.y);
+				bool[] y = bool[] (in0.z, in0.x, in0.y, in0.x, in0.y);
+				bool[13] z;
+
+				out0 = ivec3(x.length(), y.length(), z.length());
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 1.0, 2.0) ];
+			output ivec3 out0 = [ ivec3(3, 5, 13) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct test
+			{
+				float f;
+				vec3 v;
+			};
+
+			void main()
+			{
+				${SETUP}
+
+				test a = test(in0.z, vec3(in0.x, in0.y, in0.z));
+				test b = test(in0.y, vec3(-in0.z, -in0.x, -in0.y));
+				test c = test(in0.x, vec3(-in0.y, in0.z, -in0.x));
+
+				test[] x = test[3] (a, b, c);
+				test[] y = test[] (c, a, b, b, a);
+				test[13] z;
+
+				out0 = ivec3(x.length(), y.length(), z.length());
+				${OUTPUT}
+			}
+		""
+	end
+
+end # length
diff --git a/external/vulkancts/data/vulkan/glsl/es310/conditionals.test b/external/vulkancts/data/vulkan/glsl/es310/conditionals.test
new file mode 100644
index 0000000..55cc523
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/conditionals.test
@@ -0,0 +1,223 @@
+group if "If Statements"
+
+	case single_statement
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				if (in0 >= 1.0)
+					out0 = 1.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case compound_statement
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+			output float out1 = [ 1.0 | 0.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				out1 = 1.0;
+				if (in0 >= 1.0)
+				{
+					out0 = 1.0;
+					out1 = 0.0;
+				}
+				${OUTPUT}
+			}
+		""
+	end
+
+	case sequence_statements
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+			output float out1 = [ 1.0 | 0.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				out1 = 1.0;
+				if (in0 >= 1.0)
+					out0 = 1.0, out1 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case sequence_condition
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+			output float out1 = [ 1.0 | 0.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				out1 = 1.0;
+				if (false, in0 >= 1.0)
+					out0 = 1.0, out1 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case complex_condition
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+			output float out1 = [ 1.0 | 0.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				out1 = 1.0;
+				if (false || (in0 >= 1.0) && (in0 - 2.0*in0 < 0.0))
+					out0 = 1.0, out1 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case if_else
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 1.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				if (in0 >= 1.0)
+					out0 = 1.0;
+				else
+					out0 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case if_elseif
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 2.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				out0 = 0.0;
+				if (in0 >= 2.0)
+					out0 = 2.0;
+				else if (in0 >= 1.0)
+					out0 = 1.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case if_elseif_else
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 2.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				if (in0 >= 2.0)
+					out0 = 2.0;
+				else if (in0 >= 1.0)
+					out0 = 1.0;
+				else
+					out0 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mixed_if_elseif_else
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 ];
+			output float out0 = [ 0.0 | 1.0 | 2.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				if (in0 >= 2.0)
+				{
+					out0 = 2.0;
+				}
+				else if (in0 >= 1.0)
+					out0 = 2.0, out0 = 1.0;
+				else
+					out0 = 0.0;
+				${OUTPUT}
+			}
+		""
+	end
+
+end # if
diff --git a/external/vulkancts/data/vulkan/glsl/es310/constant_expressions.test b/external/vulkancts/data/vulkan/glsl/es310/constant_expressions.test
new file mode 100644
index 0000000..046eb2a
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/constant_expressions.test
@@ -0,0 +1,483 @@
+group trivial "Trivial expressions"
+
+	case float
+		version 310 es
+		values { output float out0 = 5.0; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a = 5.0;
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int
+		version 310 es
+		values { output int out0 = 5; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int a = 5;
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool
+		version 310 es
+		values { output bool out0 = true; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const bool a = true;
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case cast
+		version 310 es
+		values { output float out0 = 1.0; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a = float(int(bool(true)));
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+end # trivial
+
+group operators "Operators"
+
+	case math_float
+		version 310 es
+		values { output float out0 = 2.19; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a = 6.0/3.5 + 1.8*2.6 - 4.2;
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case math_vec
+		version 310 es
+		values { output float out0 = 15.0; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const vec3 a = (vec4(1.0, 2.0, 3.0, 4.0).zyx * vec3(1.0, 1.5, 3.0).xyz).xzy + (vec2(5.0)/vec2(2.5)).xxy;
+				out0 = a.x + a.y + a.z;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case math_int
+		version 310 es
+		values { output int out0 = 7; }
+		both ""
+			#version 310 es
+			precision highp int;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int a = 25%7 + 2*3 - 9/3;
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case math_ivec
+		version 310 es
+		values { output int out0 = 21; }
+		both ""
+			#version 310 es
+			precision highp int;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const ivec3 a = ivec2(25%7, 4).xxy + ivec4(1*3, 9/3, 1+2, 8/4).xyz;
+				out0 = a.x + a.y + a.z;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case math_mat
+		version 310 es
+		values { output float out0 = 8.0; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const mat3 a = mat3(3.0) * mat3(4.0);
+				const mat4 b = mat4(a[1][1])*2.0;
+				const mat2 c = mat2(b[0][0]) / 3.0;
+				out0 = c[0][0]+c[1][0];
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bitwise
+		version 310 es
+		values { output int out0 = 678332; }
+		both ""
+			#version 310 es
+			precision highp int;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int a = (((0xABBA<<4) ^ 0xCAFE) | (0xDCBA & (0xABCD>>2))) ^ (~0xDEAD & 0xBEEF);
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case logical
+		version 310 es
+		values { output bool out0 = true; }
+		both ""
+			#version 310 es
+			precision highp int;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const bool a = (!false || false) && (true ^^ false);
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case compare
+		version 310 es
+		values { output bool out0 = true; }
+		both ""
+			#version 310 es
+			precision highp int;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const bool a = (false == false) && (true != false) && (1 < 2) && (3 <= 3) && ((1 > 1) != (1 >= 1));
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case selection
+		version 310 es
+		values { output float out0 = 5.3; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a = false ? 0.0 : (true ? 5.3 : 1.0);
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+end # operators
+
+group complex_types "Arrays & Structs"
+
+	case struct
+		version 310 es
+		values { output float out0 = 260.922; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			struct S
+			{
+				vec4 a;
+				int  b;
+			};
+
+			void main()
+			{
+				const S s = S(vec4(1.5), 123);
+				out0 = length(s.a.xy)*float(s.b);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case nested_struct
+		version 310 es
+		values { output float out0 = 965.9; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			struct S
+			{
+				vec4 v;
+				int  i;
+			};
+
+			struct T
+			{
+				S s;
+				bool b;
+				int i;
+			};
+
+			struct U
+			{
+				S s;
+				T t;
+			};
+
+			void main()
+			{
+				const S s = S(vec4(1.5), 123);
+				const T t = T(s, false, 3);
+				const U u = U(s, t);
+				const U v = U(S(vec4(1.3), 4), T(S(vec4(2.0), 5), true, 6));
+				out0 = float(u.s.i*v.t.i + v.t.s.i)*v.s.v.x; // float(123*6 + 5)*1.3
+				${OUTPUT}
+			}
+		""
+	end
+
+	case array_size
+		version 310 es
+		values { output int out0 = 1; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int a[max(-1, 1)] = int[1](1);
+				out0 = a[0];
+				${OUTPUT}
+			}
+		""
+	end
+
+	case array_length
+		version 310 es
+		values { output int out0 = 2; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int a[1] = int[1](1);
+				out0 = a.length() + a[0];
+				${OUTPUT}
+			}
+		""
+	end
+
+	case array
+		version 310 es
+		values { output float out0 = 4.0; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a[1+2+5] = float[8](0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0);
+				const float f = a[1+2+4];
+				out0 = f + float(a.length()-8);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # complex_types
+
+group other "Other operations"
+
+	case switch_case
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.0 | 4.0 | 5.0 ];
+			output int out0 = [ 0 | 1 | 2 | 3 | 4 | 10];
+		}
+
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const int _0 = 0;
+				const int _1 = 1;
+				const int _2 = 2;
+				const int _3 = 3;
+				const int _4 = 4;
+
+				switch(int(in0))
+				{
+					case _0:
+						out0 = 0;
+						break;
+					case _1:
+						out0 = 1;
+						break;
+					case _2:
+						out0 = 2;
+						break;
+					case _3:
+						out0 = 3;
+						break;
+					case _4:
+						out0 = 4;
+						break;
+					case 5:
+						out0 = 10;
+						break;
+					default:
+						out0 = 100;
+
+				}
+				${OUTPUT}
+			}
+		""
+	end
+
+	case nested_builtin_funcs
+		version 310 es
+		values { output float out0 = 3.05; }
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			void main()
+			{
+				const float a = sqrt( atan(sin(1.5)/cos(1.5)) /*1.5*/ * log2(exp2(log(exp(6.2) + 0.1)) + 0.1) /*~6.2*/);
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case complex
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.0 | 4.0 | 5.0 ];
+			output int out0 = [ 0 | 1 | 2 | 3 | 4 | 10];
+		}
+
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			struct T
+			{
+				vec4 v;
+			};
+
+			struct S
+			{
+				T t;
+				int i;
+				bool b;
+			};
+
+			void main()
+			{
+				const T   t  = T(vec4(1.0));
+				const S   s  = S(t, 42, true);
+				const int _0 = int(sin(0.0));
+				const int _1 = int(1.0);
+				const int _2 = 2 + int(float(_0>_1));
+				const int _3 = min(gl_MaxVertexAttribs, 16)/4 - 1;
+				const int _4 = min(gl_MaxDrawBuffers, 4);
+				const ivec4 nums = ivec4(0, 1, 2, 3);
+
+				switch(int(in0))
+				{
+					case int(float(_0)):
+						out0 = ((true!=false) && (!false)) ? 0 : 25;
+						break;
+					case ivec3(_1).x:
+						out0 = 3*18/9-5;
+						break;
+					case nums[_2]:
+						out0 = int(length(vec4(1.0))+0.001);
+						break;
+					case _3:
+						out0 = 3;
+						break;
+					case clamp(_4, 1, 6):
+						out0 = (s.i-2)/10;
+						break;
+					case max(3, 5):
+						out0 = 10;
+						break;
+					default:
+						out0 = 100;
+
+				}
+				${OUTPUT}
+			}
+		""
+	end
+end
diff --git a/external/vulkancts/data/vulkan/glsl/es310/constants.test b/external/vulkancts/data/vulkan/glsl/es310/constants.test
new file mode 100644
index 0000000..2878333
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/constants.test
@@ -0,0 +1,838 @@
+case float_input
+	version 310 es
+	values
+	{
+		input float in0		= [ 1.123 | 0.75 | -512.0 | -72.13 | 199.91 | -1.123 | -0.75 | 512.0 | -72.13 | -199.91 ];
+		output float out0	= [ 1.123 | 0.75 | -512.0 | -72.13 | 199.91 | -1.123 | -0.75 | 512.0 | -72.13 | -199.91 ];
+	}
+
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = in0;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_uniform
+	version 310 es
+	values
+	{
+		uniform float uni0	= [ 1.123 | 0.75 | -512.0 | -72.13 | 199.91 ];
+		output float out0	= [ 1.123 | 0.75 | -512.0 | -72.13 | 199.91 ];
+	}
+
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = uni0;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_0
+	version 310 es
+	values { output float out0 = 1.123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = +1.123;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_1
+	version 310 es
+	values { output float out0 = -1.123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = -1.123;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_2
+	version 310 es
+	values { output float out0 = 123.0; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 123.;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_3
+	version 310 es
+	values { output float out0 = 0.123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = .123;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_4
+	version 310 es
+	values { output float out0 = 123.0; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 1.23e+2;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_5
+	version 310 es
+	values { output float out0 = -123.0; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = -1.23E+2;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_6
+	version 310 es
+	values { output float out0 = -123.0; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = -1.23e2;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_7
+	version 310 es
+	values { output float out0 = 0.123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 1.23e-1;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_8
+	version 310 es
+	values { output float out0 = 1000.0; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 1e3;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_f_suffix_0
+	version 310 es
+	values { output float out0 = 1.0; }
+	both ""
+		#version 310 es
+		precision mediump float;
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			float value = 1.0f;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case float_f_suffix_1
+	version 310 es
+	values { output float out0 = 1.0; }
+	both ""
+		#version 310 es
+		precision mediump float;
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			float value = 1.0F;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_0
+	version 310 es
+	values { output int out0 = 123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 123;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_1
+	version 310 es
+	values { output int out0 = -321; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = -321;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_2
+	version 310 es
+	values { output int out0 = 123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 0x7B;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_3
+	version 310 es
+	values { output int out0 = 123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 0X7b;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_4
+	version 310 es
+	values { output int out0 = 123; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = 0173;
+			${OUTPUT}
+		}
+	""
+end
+
+case bool_0
+	version 310 es
+	values { output bool out0 = true; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = true;
+			${OUTPUT}
+		}
+	""
+end
+
+case bool_1
+	version 310 es
+	values { output bool out0 = false; }
+	both ""
+		#version 310 es
+		precision highp float;
+		${DECLARATIONS}
+		void main()
+		{
+			out0 = false;
+			${OUTPUT}
+		}
+	""
+end
+
+case const_float_global
+	 version 310 es
+	 values { output float out0 = 1000.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = 1000.0;
+			void main()
+			{
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_main
+	 version 310 es
+	 values { output float out0 = -1000.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+					const float theConstant = -1000.0;
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_function
+	 version 310 es
+	 values { output float out0 = -0.012; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			float func()
+			{
+					const float theConstant = -0.012;
+				return theConstant;
+			}
+			void main()
+			{
+				out0 = func();
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_scope
+	 version 310 es
+	 values { output float out0 = 1.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				{
+					 const float theConstant = 1.0;
+					 out0 = theConstant;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_scope_shawdowing_1
+	 version 310 es
+	 values { output float out0 = 1.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				const float theConstant = 100.0;
+				{
+					 const float theConstant = 1.0;
+					 out0 = theConstant;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_scope_shawdowing_2
+	 version 310 es
+	 values { output float out0 = 1.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = 100.0;
+			void main()
+			{
+				{
+					 const float theConstant = 1.0;
+					 out0 = theConstant;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_scope_shawdowing_3
+	 version 310 es
+	 values { output float out0 = 1.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = 100.0;
+			void main()
+			{
+				const float theConstant = -100.0;
+				{
+					 const float theConstant = 1.0;
+					 out0 = theConstant;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_scope_shawdowing_4
+	 version 310 es
+	 values { output float out0 = 2.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = 100.0;
+			float func()
+			{
+				const float theConstant = 2.0;
+				return theConstant;
+			}
+			void main()
+			{
+				const float theConstant = -100.0;
+				{
+					 const float theConstant = 1.0;
+					 out0 = func();
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_operations_with_const
+	 version 310 es
+	 values { output float out0 = 21.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theGlobalConstant = 10.0;
+			float func()
+			{
+				const float theConstant = 2.0;
+				return theConstant;
+			}
+			void main()
+			{
+				const float theConstant = -100.0;
+				{
+					 const float theConstant = 1.0;
+					 out0 = func() * theGlobalConstant + theConstant;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_assignment_1
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				const float theConstant1 = 10.0;
+				const float theConstant2 = theConstant1;
+				out0 = theConstant2;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_assignment_2
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				const float theConstant1 = 10.0;
+				{
+					const float theConstant2 = theConstant1;
+					out0 = theConstant2;
+				}
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_assignment_3
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant1 = 10.0;
+			void main()
+			{
+				const float theConstant2 = theConstant1;
+				out0 = theConstant2;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_assignment_4
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant1 = 10.0;
+			float func()
+			{
+				const float theConstant2 = theConstant1;
+				return theConstant2;
+			}
+			void main()
+			{
+				out0 = func();
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_from_int
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = float(10);
+			void main()
+			{
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_from_vec2
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = vec2(1.0, 10.0).y;
+			void main()
+			{
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_from_vec3
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = vec3(1.0, 10.0, 20.0).y;
+			void main()
+			{
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case const_float_from_vec4
+	 version 310 es
+	 values { output float out0 = 10.0; }
+
+	 both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			const float theConstant = vec4(1.0, 10.0, 20.0, -10.0).y;
+			void main()
+			{
+				out0 = theConstant;
+				${OUTPUT}
+			}
+	 ""
+end
+
+case int_decimal
+	version 310 es
+	values { output int out0 = 7; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			int value = 7;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_octal
+	version 310 es
+	values { output int out0 = 15; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			int value = 017;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_hexadecimal_0
+	version 310 es
+	values { output int out0 = 47; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			int value = 0x2f;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case int_hexadecimal_1
+	version 310 es
+	values { output int out0 = 47; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			int value = 0X2f;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_decimal_0
+	version 310 es
+	values { output uint out0 = 7; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 7u;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_decimal_1
+	version 310 es
+	values { output uint out0 = 7; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 7U;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_decimal_2
+	version 310 es
+	values { output uint out0 = 0; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 0u;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_decimal_3
+	version 310 es
+	values { output uint out0 = 0; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 0U;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_octal_0
+	version 310 es
+	values { output uint out0 = 15; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 017u;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_octal_1
+	version 310 es
+	values { output uint out0 = 15; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 017U;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_hexadecimal_0
+	version 310 es
+	values { output uint out0 = 47; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 0x2fU;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
+
+case uint_hexadecimal_1
+	version 310 es
+	values { output uint out0 = 47; }
+	both ""
+		#version 310 es
+		${DECLARATIONS}
+		void main ()
+		{
+			${SETUP}
+			uint value = 0X2fu;
+			out0 = value;
+			${OUTPUT}
+		}
+	""
+end
diff --git a/external/vulkancts/data/vulkan/glsl/es310/conversions.test b/external/vulkancts/data/vulkan/glsl/es310/conversions.test
new file mode 100644
index 0000000..bc8ebc3
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/conversions.test
@@ -0,0 +1,13186 @@
+# WARNING: This file is auto-generated. Do NOT modify it manually, but rather
+# modify the generating script file. Otherwise changes will be lost!
+
+group scalar_to_scalar "Scalar to Scalar Conversions"
+
+	case float_to_float
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output float out0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_int
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output int out0 = [ 0 | 1 | 2 | 3 | 0 | -8 | -20 | 36 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_bool
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output bool out0 = [ false | true | true | true | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_float
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output float out0 = [ 0.0 | 1.0 | 2.0 | 5.0 | 8.0 | 11.0 | -12.0 | -66.0 | -192.0 | 255.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_int
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output int out0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_bool
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output bool out0 = [ false | true | true | true | true | true | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_float
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output float out0 = [ 0.0 | 2.0 | 3.0 | 8.0 | 9.0 | 12.0 | 10.0 | 45.0 | 193.0 | 255.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_int
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output int out0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_bool
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output bool out0 = [ false | true | true | true | true | true | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_float
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output float out0 = [ 1.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_int
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output int out0 = [ 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_bool
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output bool out0 = [ true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_uint
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | 0.5 | 8.25 | 20.125 | 36.8125 ];
+			output uint out0 = [ 0 | 1 | 2 | 3 | 0 | 8 | 20 | 36 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_uint
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | 12 | 66 | 192 | 255 ];
+			output uint out0 = [ 0 | 1 | 2 | 5 | 8 | 11 | 12 | 66 | 192 | 255 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_uint
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output uint out0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_uint
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output uint out0 = [ 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # scalar_to_scalar
+group scalar_to_vector "Scalar to Vector Conversions"
+
+	case float_to_vec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(2.0, 2.0) | vec2(3.5, 3.5) | vec2(-0.5, -0.5) | vec2(-8.25, -8.25) | vec2(-20.125, -20.125) | vec2(36.8125, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_vec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(2.0, 2.0, 2.0) | vec3(3.5, 3.5, 3.5) | vec3(-0.5, -0.5, -0.5) | vec3(-8.25, -8.25, -8.25) | vec3(-20.125, -20.125, -20.125) | vec3(36.8125, 36.8125, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_vec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(2.0, 2.0, 2.0, 2.0) | vec4(3.5, 3.5, 3.5, 3.5) | vec4(-0.5, -0.5, -0.5, -0.5) | vec4(-8.25, -8.25, -8.25, -8.25) | vec4(-20.125, -20.125, -20.125, -20.125) | vec4(36.8125, 36.8125, 36.8125, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_ivec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(2, 2) | ivec2(3, 3) | ivec2(0, 0) | ivec2(-8, -8) | ivec2(-20, -20) | ivec2(36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_ivec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(2, 2, 2) | ivec3(3, 3, 3) | ivec3(0, 0, 0) | ivec3(-8, -8, -8) | ivec3(-20, -20, -20) | ivec3(36, 36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_ivec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(2, 2, 2, 2) | ivec4(3, 3, 3, 3) | ivec4(0, 0, 0, 0) | ivec4(-8, -8, -8, -8) | ivec4(-20, -20, -20, -20) | ivec4(36, 36, 36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_bvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_bvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_bvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_vec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(2.0, 2.0) | vec2(5.0, 5.0) | vec2(8.0, 8.0) | vec2(11.0, 11.0) | vec2(-12.0, -12.0) | vec2(-66.0, -66.0) | vec2(-192.0, -192.0) | vec2(255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_vec3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(2.0, 2.0, 2.0) | vec3(5.0, 5.0, 5.0) | vec3(8.0, 8.0, 8.0) | vec3(11.0, 11.0, 11.0) | vec3(-12.0, -12.0, -12.0) | vec3(-66.0, -66.0, -66.0) | vec3(-192.0, -192.0, -192.0) | vec3(255.0, 255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_vec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(2.0, 2.0, 2.0, 2.0) | vec4(5.0, 5.0, 5.0, 5.0) | vec4(8.0, 8.0, 8.0, 8.0) | vec4(11.0, 11.0, 11.0, 11.0) | vec4(-12.0, -12.0, -12.0, -12.0) | vec4(-66.0, -66.0, -66.0, -66.0) | vec4(-192.0, -192.0, -192.0, -192.0) | vec4(255.0, 255.0, 255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_ivec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(2, 2) | ivec2(5, 5) | ivec2(8, 8) | ivec2(11, 11) | ivec2(-12, -12) | ivec2(-66, -66) | ivec2(-192, -192) | ivec2(255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_ivec3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(2, 2, 2) | ivec3(5, 5, 5) | ivec3(8, 8, 8) | ivec3(11, 11, 11) | ivec3(-12, -12, -12) | ivec3(-66, -66, -66) | ivec3(-192, -192, -192) | ivec3(255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_ivec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(2, 2, 2, 2) | ivec4(5, 5, 5, 5) | ivec4(8, 8, 8, 8) | ivec4(11, 11, 11, 11) | ivec4(-12, -12, -12, -12) | ivec4(-66, -66, -66, -66) | ivec4(-192, -192, -192, -192) | ivec4(255, 255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_bvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_bvec3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_bvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_vec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(2.0, 2.0) | vec2(3.0, 3.0) | vec2(8.0, 8.0) | vec2(9.0, 9.0) | vec2(12.0, 12.0) | vec2(10.0, 10.0) | vec2(45.0, 45.0) | vec2(193.0, 193.0) | vec2(255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_vec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(2.0, 2.0, 2.0) | vec3(3.0, 3.0, 3.0) | vec3(8.0, 8.0, 8.0) | vec3(9.0, 9.0, 9.0) | vec3(12.0, 12.0, 12.0) | vec3(10.0, 10.0, 10.0) | vec3(45.0, 45.0, 45.0) | vec3(193.0, 193.0, 193.0) | vec3(255.0, 255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_vec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(2.0, 2.0, 2.0, 2.0) | vec4(3.0, 3.0, 3.0, 3.0) | vec4(8.0, 8.0, 8.0, 8.0) | vec4(9.0, 9.0, 9.0, 9.0) | vec4(12.0, 12.0, 12.0, 12.0) | vec4(10.0, 10.0, 10.0, 10.0) | vec4(45.0, 45.0, 45.0, 45.0) | vec4(193.0, 193.0, 193.0, 193.0) | vec4(255.0, 255.0, 255.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_ivec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(2, 2) | ivec2(3, 3) | ivec2(8, 8) | ivec2(9, 9) | ivec2(12, 12) | ivec2(10, 10) | ivec2(45, 45) | ivec2(193, 193) | ivec2(255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_ivec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(2, 2, 2) | ivec3(3, 3, 3) | ivec3(8, 8, 8) | ivec3(9, 9, 9) | ivec3(12, 12, 12) | ivec3(10, 10, 10) | ivec3(45, 45, 45) | ivec3(193, 193, 193) | ivec3(255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_ivec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(2, 2, 2, 2) | ivec4(3, 3, 3, 3) | ivec4(8, 8, 8, 8) | ivec4(9, 9, 9, 9) | ivec4(12, 12, 12, 12) | ivec4(10, 10, 10, 10) | ivec4(45, 45, 45, 45) | ivec4(193, 193, 193, 193) | ivec4(255, 255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_bvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_bvec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_bvec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_vec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output vec2 out0 = [ vec2(1.0, 1.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_vec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output vec3 out0 = [ vec3(1.0, 1.0, 1.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_vec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output vec4 out0 = [ vec4(1.0, 1.0, 1.0, 1.0) | vec4(0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_ivec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output ivec2 out0 = [ ivec2(1, 1) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_ivec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output ivec3 out0 = [ ivec3(1, 1, 1) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_ivec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output ivec4 out0 = [ ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_bvec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_bvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_bvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_uvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | 0.5 | 8.25 | 20.125 | 36.8125 ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(2, 2) | uvec2(3, 3) | uvec2(0, 0) | uvec2(8, 8) | uvec2(20, 20) | uvec2(36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_uvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | 0.5 | 8.25 | 20.125 | 36.8125 ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(2, 2, 2) | uvec3(3, 3, 3) | uvec3(0, 0, 0) | uvec3(8, 8, 8) | uvec3(20, 20, 20) | uvec3(36, 36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_uvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | 0.5 | 8.25 | 20.125 | 36.8125 ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(2, 2, 2, 2) | uvec4(3, 3, 3, 3) | uvec4(0, 0, 0, 0) | uvec4(8, 8, 8, 8) | uvec4(20, 20, 20, 20) | uvec4(36, 36, 36, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_uvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | 12 | 66 | 192 | 255 ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(2, 2) | uvec2(5, 5) | uvec2(8, 8) | uvec2(11, 11) | uvec2(12, 12) | uvec2(66, 66) | uvec2(192, 192) | uvec2(255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_uvec3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | 12 | 66 | 192 | 255 ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(2, 2, 2) | uvec3(5, 5, 5) | uvec3(8, 8, 8) | uvec3(11, 11, 11) | uvec3(12, 12, 12) | uvec3(66, 66, 66) | uvec3(192, 192, 192) | uvec3(255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_uvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | 12 | 66 | 192 | 255 ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(2, 2, 2, 2) | uvec4(5, 5, 5, 5) | uvec4(8, 8, 8, 8) | uvec4(11, 11, 11, 11) | uvec4(12, 12, 12, 12) | uvec4(66, 66, 66, 66) | uvec4(192, 192, 192, 192) | uvec4(255, 255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_uvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(2, 2) | uvec2(3, 3) | uvec2(8, 8) | uvec2(9, 9) | uvec2(12, 12) | uvec2(10, 10) | uvec2(45, 45) | uvec2(193, 193) | uvec2(255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_uvec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(2, 2, 2) | uvec3(3, 3, 3) | uvec3(8, 8, 8) | uvec3(9, 9, 9) | uvec3(12, 12, 12) | uvec3(10, 10, 10) | uvec3(45, 45, 45) | uvec3(193, 193, 193) | uvec3(255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_uvec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(2, 2, 2, 2) | uvec4(3, 3, 3, 3) | uvec4(8, 8, 8, 8) | uvec4(9, 9, 9, 9) | uvec4(12, 12, 12, 12) | uvec4(10, 10, 10, 10) | uvec4(45, 45, 45, 45) | uvec4(193, 193, 193, 193) | uvec4(255, 255, 255, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_uvec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output uvec2 out0 = [ uvec2(1, 1) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_uvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output uvec3 out0 = [ uvec3(1, 1, 1) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_uvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output uvec4 out0 = [ uvec4(1, 1, 1, 1) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # scalar_to_vector
+group vector_to_scalar "Vector to Scalar Conversions"
+
+	case vec2_to_float
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_int
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_bool
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output bool out0 = [ false | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_float
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_int
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_bool
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output bool out0 = [ false | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_float
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_int
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_bool
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output bool out0 = [ false | true | true | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_float
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | -32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_int
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_bool
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_float
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | -32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_int
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_bool
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_float
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | -32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_int
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_bool
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_float
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | 32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_int
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_bool
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_float
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | 32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_int
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_bool
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_float
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output float out0 = [ 0.0 | 1.0 | 0.0 | 32.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_int
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_bool
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output bool out0 = [ false | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_float
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output float out0 = [ 1.0 | 0.0 | 0.0 | 1.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_int
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output int out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_bool
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_float
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output float out0 = [ 1.0 | 0.0 | 0.0 | 1.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_int
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output int out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_bool
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_float
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output float out0 = [ 1.0 | 0.0 | 0.0 | 1.0 | 0.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = float(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_int
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output int out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = int(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_bool
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bool(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_uint
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(0.5, 2.25) | vec2(32.0, 64.0) | vec2(0.75, 0.0322580645161) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_uint
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(0.5, 2.25, 4.875) | vec3(32.0, 64.0, 51.0) | vec3(0.75, 0.0322580645161, 0.0526315789474) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_uint
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.5, 2.25, 4.875, 9.0) | vec4(32.0, 64.0, 51.0, 24.0) | vec4(0.75, 0.0322580645161, 0.0526315789474, 0.25) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_uint
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_uint
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 2, 4) | ivec3(32, 64, 51) | ivec3(0, 0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_uint
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 2, 4, 9) | ivec4(32, 64, 51, 24) | ivec4(0, 0, 0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_uint
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_uint
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_uint
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output uint out0 = [ 0 | 1 | 0 | 32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_uint
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output uint out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_uint
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output uint out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_uint
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output uint out0 = [ 1 | 0 | 0 | 1 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uint(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # vector_to_scalar
+
+group vector_to_vector "Vector to Vector Conversions"
+
+	case vec4_to_vec4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_vec3
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_vec2
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_ivec4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_ivec3
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_ivec2
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_bvec4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output bvec4 out0 = [ bvec4(false, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_bvec3
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output bvec3 out0 = [ bvec3(false, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_bvec2
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_vec4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(0.0, -2.0, -4.0, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_vec3
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, -2.0, -4.0) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_vec2
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, -2.0) | vec2(-32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_ivec4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_ivec3
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_ivec2
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_bvec4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_bvec3
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_bvec2
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_vec4
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(0.0, 2.0, 4.0, 9.0) | vec4(32.0, 64.0, 51.0, 24.0) | vec4(0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_vec3
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, 2.0, 4.0) | vec3(32.0, 64.0, 51.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_vec2
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, 2.0) | vec2(32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_ivec4
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 2, 4, 9) | ivec4(32, 64, 51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_ivec3
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 2, 4) | ivec3(32, 64, 51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_ivec2
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_bvec4
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_bvec3
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_bvec2
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_vec4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output vec4 out0 = [ vec4(1.0, 0.0, 0.0, 1.0) | vec4(0.0, 0.0, 0.0, 1.0) | vec4(0.0, 1.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_vec3
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output vec3 out0 = [ vec3(1.0, 0.0, 0.0) | vec3(0.0, 0.0, 0.0) | vec3(0.0, 1.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_vec2
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output vec2 out0 = [ vec2(1.0, 0.0) | vec2(0.0, 0.0) | vec2(0.0, 1.0) | vec2(1.0, 1.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_ivec4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output ivec4 out0 = [ ivec4(1, 0, 0, 1) | ivec4(0, 0, 0, 1) | ivec4(0, 1, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_ivec3
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output ivec3 out0 = [ ivec3(1, 0, 0) | ivec3(0, 0, 0) | ivec3(0, 1, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_ivec2
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output ivec2 out0 = [ ivec2(1, 0) | ivec2(0, 0) | ivec2(0, 1) | ivec2(1, 1) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_bvec4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_bvec3
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_bvec2
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_uvec4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.5, 2.25, 4.875, 9.0) | vec4(32.0, 64.0, 51.0, 24.0) | vec4(0.75, 0.0322580645161, 0.0526315789474, 0.25) ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_uvec3
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.5, 2.25, 4.875, 9.0) | vec4(32.0, 64.0, 51.0, 24.0) | vec4(0.75, 0.0322580645161, 0.0526315789474, 0.25) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_to_uvec2
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.5, 2.25, 4.875, 9.0) | vec4(32.0, 64.0, 51.0, 24.0) | vec4(0.75, 0.0322580645161, 0.0526315789474, 0.25) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_uvec4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 2, 4, 9) | ivec4(32, 64, 51, 24) | ivec4(0, 0, 0, 0) ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_uvec3
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 2, 4, 9) | ivec4(32, 64, 51, 24) | ivec4(0, 0, 0, 0) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_to_uvec2
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 2, 4, 9) | ivec4(32, 64, 51, 24) | ivec4(0, 0, 0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_uvec4
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output uvec4 out0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_uvec3
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec4_to_uvec2
+		version 310 es
+		values
+		{
+			input uvec4 in0 = [ uvec4(0, 0, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 2, 4, 9) | uvec4(32, 64, 51, 24) | uvec4(0, 0, 0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_uvec4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output uvec4 out0 = [ uvec4(1, 0, 0, 1) | uvec4(0, 0, 0, 1) | uvec4(0, 1, 0, 0) | uvec4(1, 1, 1, 1) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_uvec3
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output uvec3 out0 = [ uvec3(1, 0, 0) | uvec3(0, 0, 0) | uvec3(0, 1, 0) | uvec3(1, 1, 1) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_to_uvec2
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output uvec2 out0 = [ uvec2(1, 0) | uvec2(0, 0) | uvec2(0, 1) | uvec2(1, 1) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_vec2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_ivec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_ivec2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_bvec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output bvec3 out0 = [ bvec3(false, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_bvec2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_vec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, -2.0, -4.0) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_vec2
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, -2.0) | vec2(-32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_ivec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_ivec2
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_bvec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_bvec2
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_vec3
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, 2.0, 4.0) | vec3(32.0, 64.0, 51.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_vec2
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, 2.0) | vec2(32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_ivec3
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 2, 4) | ivec3(32, 64, 51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_ivec2
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_bvec3
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_bvec2
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_vec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output vec3 out0 = [ vec3(1.0, 0.0, 0.0) | vec3(0.0, 0.0, 0.0) | vec3(0.0, 1.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_vec2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output vec2 out0 = [ vec2(1.0, 0.0) | vec2(0.0, 0.0) | vec2(0.0, 1.0) | vec2(1.0, 1.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_ivec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output ivec3 out0 = [ ivec3(1, 0, 0) | ivec3(0, 0, 0) | ivec3(0, 1, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_ivec2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output ivec2 out0 = [ ivec2(1, 0) | ivec2(0, 0) | ivec2(0, 1) | ivec2(1, 1) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_bvec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_bvec2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_uvec3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(0.5, 2.25, 4.875) | vec3(32.0, 64.0, 51.0) | vec3(0.75, 0.0322580645161, 0.0526315789474) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_to_uvec2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(0.5, 2.25, 4.875) | vec3(32.0, 64.0, 51.0) | vec3(0.75, 0.0322580645161, 0.0526315789474) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_uvec3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 2, 4) | ivec3(32, 64, 51) | ivec3(0, 0, 0) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_to_uvec2
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 2, 4) | ivec3(32, 64, 51) | ivec3(0, 0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_uvec3
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec3_to_uvec2
+		version 310 es
+		values
+		{
+			input uvec3 in0 = [ uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_uvec3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output uvec3 out0 = [ uvec3(1, 0, 0) | uvec3(0, 0, 0) | uvec3(0, 1, 0) | uvec3(1, 1, 1) | uvec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_to_uvec2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output uvec2 out0 = [ uvec2(1, 0) | uvec2(0, 0) | uvec2(0, 1) | uvec2(1, 1) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_vec2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_ivec2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_bvec2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_vec2
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, -2.0) | vec2(-32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_ivec2
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_bvec2
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_vec2
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(0.0, 2.0) | vec2(32.0, 64.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_ivec2
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_bvec2
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_vec2
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output vec2 out0 = [ vec2(1.0, 0.0) | vec2(0.0, 0.0) | vec2(0.0, 1.0) | vec2(1.0, 1.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_ivec2
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output ivec2 out0 = [ ivec2(1, 0) | ivec2(0, 0) | ivec2(0, 1) | ivec2(1, 1) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_bvec2
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_to_uvec2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(0.5, 2.25) | vec2(32.0, 64.0) | vec2(0.75, 0.0322580645161) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec2_to_uvec2
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uvec2_to_uvec2
+		version 310 es
+		values
+		{
+			input uvec2 in0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+			output uvec2 out0 = [ uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_to_uvec2
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output uvec2 out0 = [ uvec2(1, 0) | uvec2(0, 0) | uvec2(0, 1) | uvec2(1, 1) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # vector_to_vector
+group scalar_to_matrix "Scalar to Matrix Conversions"
+
+	case float_to_mat4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat4 out0 = [ mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0) | mat4(3.5, 0.0, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 0.0, 3.5) | mat4(-0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, -0.5) | mat4(-8.25, 0.0, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, 0.0, -8.25) | mat4(-20.125, 0.0, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, 0.0, -20.125) | mat4(36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat4x3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat4x3 out0 = [ mat4x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0) | mat4x3(3.5, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0) | mat4x3(-0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0) | mat4x3(-8.25, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0) | mat4x3(-20.125, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0) | mat4x3(36.8125, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat4x2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat4x2 out0 = [ mat4x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(3.5, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 0.0) | mat4x2(-0.5, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0) | mat4x2(-8.25, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, 0.0) | mat4x2(-20.125, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, 0.0) | mat4x2(36.8125, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat3x4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat3x4 out0 = [ mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat3x4(3.5, 0.0, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 0.0, 3.5, 0.0) | mat3x4(-0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0) | mat3x4(-8.25, 0.0, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, 0.0, -8.25, 0.0) | mat3x4(-20.125, 0.0, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, 0.0, -20.125, 0.0) | mat3x4(36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat3 out0 = [ mat3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0) | mat3(3.5, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0, 0.0, 3.5) | mat3(-0.5, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, -0.5) | mat3(-8.25, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, -8.25) | mat3(-20.125, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0, 0.0, -20.125) | mat3(36.8125, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0, 0.0, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat3x2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat3x2(3.5, 0.0, 0.0, 3.5, 0.0, 0.0) | mat3x2(-0.5, 0.0, 0.0, -0.5, 0.0, 0.0) | mat3x2(-8.25, 0.0, 0.0, -8.25, 0.0, 0.0) | mat3x2(-20.125, 0.0, 0.0, -20.125, 0.0, 0.0) | mat3x2(36.8125, 0.0, 0.0, 36.8125, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat2x4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat2x4 out0 = [ mat2x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat2x4(3.5, 0.0, 0.0, 0.0, 0.0, 3.5, 0.0, 0.0) | mat2x4(-0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0) | mat2x4(-8.25, 0.0, 0.0, 0.0, 0.0, -8.25, 0.0, 0.0) | mat2x4(-20.125, 0.0, 0.0, 0.0, 0.0, -20.125, 0.0, 0.0) | mat2x4(36.8125, 0.0, 0.0, 0.0, 0.0, 36.8125, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat2x3
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat2x3(3.5, 0.0, 0.0, 0.0, 3.5, 0.0) | mat2x3(-0.5, 0.0, 0.0, 0.0, -0.5, 0.0) | mat2x3(-8.25, 0.0, 0.0, 0.0, -8.25, 0.0) | mat2x3(-20.125, 0.0, 0.0, 0.0, -20.125, 0.0) | mat2x3(36.8125, 0.0, 0.0, 0.0, 36.8125, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_to_mat2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -8.25 | -20.125 | 36.8125 ];
+			output mat2 out0 = [ mat2(0.0, 0.0, 0.0, 0.0) | mat2(1.0, 0.0, 0.0, 1.0) | mat2(2.0, 0.0, 0.0, 2.0) | mat2(3.5, 0.0, 0.0, 3.5) | mat2(-0.5, 0.0, 0.0, -0.5) | mat2(-8.25, 0.0, 0.0, -8.25) | mat2(-20.125, 0.0, 0.0, -20.125) | mat2(36.8125, 0.0, 0.0, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat4 out0 = [ mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0) | mat4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0) | mat4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0) | mat4(11.0, 0.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 0.0, 11.0) | mat4(-12.0, 0.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, 0.0, -12.0) | mat4(-66.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, 0.0, -66.0) | mat4(-192.0, 0.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, 0.0, -192.0) | mat4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat4x3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat4x3 out0 = [ mat4x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0) | mat4x3(5.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0) | mat4x3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0) | mat4x3(11.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0) | mat4x3(-12.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0) | mat4x3(-66.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0) | mat4x3(-192.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0) | mat4x3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat4x2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat4x2 out0 = [ mat4x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(5.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(8.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(11.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(-12.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(-66.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(-192.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(255.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat3x4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat3x4 out0 = [ mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat3x4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0) | mat3x4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0) | mat3x4(11.0, 0.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 0.0, 11.0, 0.0) | mat3x4(-12.0, 0.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, 0.0, -12.0, 0.0) | mat3x4(-66.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0) | mat3x4(-192.0, 0.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, 0.0, -192.0, 0.0) | mat3x4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat3 out0 = [ mat3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0) | mat3(5.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 5.0) | mat3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 8.0) | mat3(11.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0, 0.0, 11.0) | mat3(-12.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0, 0.0, -12.0) | mat3(-66.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0, 0.0, -66.0) | mat3(-192.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0, 0.0, -192.0) | mat3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat3x2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat3x2(5.0, 0.0, 0.0, 5.0, 0.0, 0.0) | mat3x2(8.0, 0.0, 0.0, 8.0, 0.0, 0.0) | mat3x2(11.0, 0.0, 0.0, 11.0, 0.0, 0.0) | mat3x2(-12.0, 0.0, 0.0, -12.0, 0.0, 0.0) | mat3x2(-66.0, 0.0, 0.0, -66.0, 0.0, 0.0) | mat3x2(-192.0, 0.0, 0.0, -192.0, 0.0, 0.0) | mat3x2(255.0, 0.0, 0.0, 255.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat2x4
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat2x4 out0 = [ mat2x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat2x4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0) | mat2x4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0) | mat2x4(11.0, 0.0, 0.0, 0.0, 0.0, 11.0, 0.0, 0.0) | mat2x4(-12.0, 0.0, 0.0, 0.0, 0.0, -12.0, 0.0, 0.0) | mat2x4(-66.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.0) | mat2x4(-192.0, 0.0, 0.0, 0.0, 0.0, -192.0, 0.0, 0.0) | mat2x4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat2x3
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat2x3(5.0, 0.0, 0.0, 0.0, 5.0, 0.0) | mat2x3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0) | mat2x3(11.0, 0.0, 0.0, 0.0, 11.0, 0.0) | mat2x3(-12.0, 0.0, 0.0, 0.0, -12.0, 0.0) | mat2x3(-66.0, 0.0, 0.0, 0.0, -66.0, 0.0) | mat2x3(-192.0, 0.0, 0.0, 0.0, -192.0, 0.0) | mat2x3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_to_mat2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 1 | 2 | 5 | 8 | 11 | -12 | -66 | -192 | 255 ];
+			output mat2 out0 = [ mat2(0.0, 0.0, 0.0, 0.0) | mat2(1.0, 0.0, 0.0, 1.0) | mat2(2.0, 0.0, 0.0, 2.0) | mat2(5.0, 0.0, 0.0, 5.0) | mat2(8.0, 0.0, 0.0, 8.0) | mat2(11.0, 0.0, 0.0, 11.0) | mat2(-12.0, 0.0, 0.0, -12.0) | mat2(-66.0, 0.0, 0.0, -66.0) | mat2(-192.0, 0.0, 0.0, -192.0) | mat2(255.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat4 out0 = [ mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0) | mat4(3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 3.0) | mat4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0) | mat4(9.0, 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0, 9.0) | mat4(12.0, 0.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0, 12.0) | mat4(10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 10.0) | mat4(45.0, 0.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 0.0, 45.0) | mat4(193.0, 0.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 0.0, 193.0) | mat4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat4x3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat4x3 out0 = [ mat4x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0) | mat4x3(3.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0) | mat4x3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0) | mat4x3(9.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0) | mat4x3(12.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0) | mat4x3(10.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0) | mat4x3(45.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0) | mat4x3(193.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0) | mat4x3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat4x2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat4x2 out0 = [ mat4x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(8.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(9.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(12.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(10.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(45.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(193.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(255.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat3x4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat3x4 out0 = [ mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat3x4(3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0) | mat3x4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0) | mat3x4(9.0, 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0, 9.0, 0.0) | mat3x4(12.0, 0.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0, 12.0, 0.0) | mat3x4(10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0) | mat3x4(45.0, 0.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 0.0, 45.0, 0.0) | mat3x4(193.0, 0.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 0.0, 193.0, 0.0) | mat3x4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat3 out0 = [ mat3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0) | mat3(3.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 3.0) | mat3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 8.0) | mat3(9.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 9.0) | mat3(12.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 12.0) | mat3(10.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 10.0) | mat3(45.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0, 0.0, 45.0) | mat3(193.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0, 0.0, 193.0) | mat3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat3x2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat3x2(3.0, 0.0, 0.0, 3.0, 0.0, 0.0) | mat3x2(8.0, 0.0, 0.0, 8.0, 0.0, 0.0) | mat3x2(9.0, 0.0, 0.0, 9.0, 0.0, 0.0) | mat3x2(12.0, 0.0, 0.0, 12.0, 0.0, 0.0) | mat3x2(10.0, 0.0, 0.0, 10.0, 0.0, 0.0) | mat3x2(45.0, 0.0, 0.0, 45.0, 0.0, 0.0) | mat3x2(193.0, 0.0, 0.0, 193.0, 0.0, 0.0) | mat3x2(255.0, 0.0, 0.0, 255.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat2x4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat2x4 out0 = [ mat2x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x4(2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat2x4(3.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0) | mat2x4(8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0) | mat2x4(9.0, 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 0.0) | mat2x4(12.0, 0.0, 0.0, 0.0, 0.0, 12.0, 0.0, 0.0) | mat2x4(10.0, 0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0) | mat2x4(45.0, 0.0, 0.0, 0.0, 0.0, 45.0, 0.0, 0.0) | mat2x4(193.0, 0.0, 0.0, 0.0, 0.0, 193.0, 0.0, 0.0) | mat2x4(255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat2x3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x3(2.0, 0.0, 0.0, 0.0, 2.0, 0.0) | mat2x3(3.0, 0.0, 0.0, 0.0, 3.0, 0.0) | mat2x3(8.0, 0.0, 0.0, 0.0, 8.0, 0.0) | mat2x3(9.0, 0.0, 0.0, 0.0, 9.0, 0.0) | mat2x3(12.0, 0.0, 0.0, 0.0, 12.0, 0.0) | mat2x3(10.0, 0.0, 0.0, 0.0, 10.0, 0.0) | mat2x3(45.0, 0.0, 0.0, 0.0, 45.0, 0.0) | mat2x3(193.0, 0.0, 0.0, 0.0, 193.0, 0.0) | mat2x3(255.0, 0.0, 0.0, 0.0, 255.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_to_mat2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 0 | 2 | 3 | 8 | 9 | 12 | 10 | 45 | 193 | 255 ];
+			output mat2 out0 = [ mat2(0.0, 0.0, 0.0, 0.0) | mat2(2.0, 0.0, 0.0, 2.0) | mat2(3.0, 0.0, 0.0, 3.0) | mat2(8.0, 0.0, 0.0, 8.0) | mat2(9.0, 0.0, 0.0, 9.0) | mat2(12.0, 0.0, 0.0, 12.0) | mat2(10.0, 0.0, 0.0, 10.0) | mat2(45.0, 0.0, 0.0, 45.0) | mat2(193.0, 0.0, 0.0, 193.0) | mat2(255.0, 0.0, 0.0, 255.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat4x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat4x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat3x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat3x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat2x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat2x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_to_mat2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # scalar_to_matrix
+group matrix_to_matrix "Matrix to Matrix Conversions"
+
+	case mat4_to_mat4
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat3
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4_to_mat2
+		version 310 es
+		values
+		{
+			input mat4 in0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 9.975, -6.542, 0.015625, 9.975) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat4
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, -0.75, -8.425, 0.03125, 0.0, 9.975, -6.542, 0.015625, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, -0.75, -8.425, 0.03125, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat3
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x3_to_mat2
+		version 310 es
+		values
+		{
+			input mat4x3 in0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 9.975, -6.542, 0.015625) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat4
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0, -0.75, -8.425, 1.0, 0.0, 9.975, -6.542, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0, -0.75, -8.425, 1.0, 9.975, -6.542, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0, -0.75, -8.425, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat3
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0, -0.75, -8.425, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat4x2_to_mat2
+		version 310 es
+		values
+		{
+			input mat4x2 in0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 9.975, -6.542) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat4
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat3
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x4_to_mat2
+		version 310 es
+		values
+		{
+			input mat3x4 in0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, -0.75, -8.425, 0.03125, -0.0125) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat4
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, -0.75, -8.425, 0.03125, 0.0, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, -0.75, -8.425, 0.03125, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat3
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3_to_mat2
+		version 310 es
+		values
+		{
+			input mat3 in0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, -0.75, -8.425, 0.03125) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat4
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0, -0.75, -8.425, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0, -0.75, -8.425, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0, -0.75, -8.425, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat3
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0, -0.75, -8.425, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.0, 0.0, 12.5, 0.0208333333333, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.0, 12.5, 0.0208333333333, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat3x2_to_mat2
+		version 310 es
+		values
+		{
+			input mat3x2 in0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, -0.75, -8.425) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat4
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5, 0.0, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat3
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x4_to_mat2
+		version 310 es
+		values
+		{
+			input mat2x4 in0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, -6.725, 12.5, 0.0208333333333, 0.0625, -0.5) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat4
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, 32.0, 12.5, 0.0208333333333, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat3
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, 32.0, 12.5, 0.0208333333333, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, 32.0, 0.125, 0.0, 12.5, 0.0208333333333, 0.0625, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2x3_to_mat2
+		version 310 es
+		values
+		{
+			input mat2x3 in0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, 32.0, 0.125, 12.5, 0.0208333333333, 0.0625) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, 32.0, 12.5, 0.0208333333333) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat4
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat4 out0 = [ mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(8.0, -24.0, 0.0, 0.0, 16.0, -16.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(0.125, 0.03125, 0.0, 0.0, 0.0625, 0.015625, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(-18.725, -0.0125, 0.0, 0.0, -0.5, 19.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat4x3
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(8.0, -24.0, 0.0, 16.0, -16.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(0.125, 0.03125, 0.0, 0.0625, 0.015625, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat4x3(-18.725, -0.0125, 0.0, -0.5, 19.975, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat4x2
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, -0.75, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0) | mat4x2(6.5, -0.75, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0) | mat4x2(8.0, -24.0, 16.0, -16.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(0.125, 0.03125, 0.0625, 0.015625, 0.0, 0.0, 0.0, 0.0) | mat4x2(-18.725, -0.0125, -0.5, 19.975, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat3x4
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat3x4 out0 = [ mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(8.0, -24.0, 0.0, 0.0, 16.0, -16.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(0.125, 0.03125, 0.0, 0.0, 0.0625, 0.015625, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(-18.725, -0.0125, 0.0, 0.0, -0.5, 19.975, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat3
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 1.0) | mat3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0, 0.0, 0.0, 1.0) | mat3(8.0, -24.0, 0.0, 16.0, -16.0, 0.0, 0.0, 0.0, 1.0) | mat3(0.125, 0.03125, 0.0, 0.0625, 0.015625, 0.0, 0.0, 0.0, 1.0) | mat3(-18.725, -0.0125, 0.0, -0.5, 19.975, 0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat3x2
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat3x2(6.5, -0.75, 12.5, 9.975, 0.0, 0.0) | mat3x2(6.5, -0.75, 12.5, 9.975, 0.0, 0.0) | mat3x2(8.0, -24.0, 16.0, -16.0, 0.0, 0.0) | mat3x2(0.125, 0.03125, 0.0625, 0.015625, 0.0, 0.0) | mat3x2(-18.725, -0.0125, -0.5, 19.975, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat2x4
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0) | mat2x4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0) | mat2x4(6.5, -0.75, 0.0, 0.0, 12.5, 9.975, 0.0, 0.0) | mat2x4(8.0, -24.0, 0.0, 0.0, 16.0, -16.0, 0.0, 0.0) | mat2x4(0.125, 0.03125, 0.0, 0.0, 0.0625, 0.015625, 0.0, 0.0) | mat2x4(-18.725, -0.0125, 0.0, 0.0, -0.5, 19.975, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat2x3
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat2x3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0) | mat2x3(6.5, -0.75, 0.0, 12.5, 9.975, 0.0) | mat2x3(8.0, -24.0, 0.0, 16.0, -16.0, 0.0) | mat2x3(0.125, 0.03125, 0.0, 0.0625, 0.015625, 0.0) | mat2x3(-18.725, -0.0125, 0.0, -0.5, 19.975, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2_to_mat2
+		version 310 es
+		values
+		{
+			input mat2 in0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 1.0) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(6.5, -0.75, 12.5, 9.975) | mat2(8.0, -24.0, 16.0, -16.0) | mat2(0.125, 0.03125, 0.0625, 0.015625) | mat2(-18.725, -0.0125, -0.5, 19.975) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # matrix_to_matrix
+group vector_combine "Vector Combine Constructors"
+
+	case vec2_vec2_to_vec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) ];
+			input vec2 in1 = [ vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(-0.5, -2.25, -32.0, 64.0) | vec4(-32.0, 64.0, 1.0, 1.25) | vec4(1.0, 1.25, 0.0, 0.5) | vec4(0.0, 0.5, -0.5, -2.25) | vec4(-0.75, -0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_vec2_to_ivec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) ];
+			input vec2 in1 = [ vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) ];
+			output ivec4 out0 = [ ivec4(0, -2, -32, 64) | ivec4(-32, 64, 1, 1) | ivec4(1, 1, 0, 0) | ivec4(0, 0, 0, -2) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_vec2_to_bvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) ];
+			input vec2 in1 = [ vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, false, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_bvec2_to_vec4
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input bvec2 in1 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 1.0, 0.0) | vec4(1.0, 0.0, 0.0, 0.0) | vec4(0.0, 1.0, 0.0, 1.0) | vec4(0.0, 0.0, 1.0, 1.0) | vec4(1.0, 1.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_bvec2_to_ivec4
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input bvec2 in1 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output ivec4 out0 = [ ivec4(0, 0, 1, 0) | ivec4(1, 0, 0, 0) | ivec4(0, 1, 0, 1) | ivec4(0, 0, 1, 1) | ivec4(1, 1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_bvec2_to_bvec4
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input bvec2 in1 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(true, false, false, false) | bvec4(false, true, false, true) | bvec4(false, false, true, true) | bvec4(true, true, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_to_vec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | 0.0 | -0.5 | -8.25 | 3.5 | -20.125 | 36.8125 | 2.0 ];
+			input float in1 = [ 0.0 | 36.8125 | -8.25 | 2.0 | 3.5 | 1.0 | -20.125 | -0.5 ];
+			input float in2 = [ 3.5 | 36.8125 | -8.25 | 1.0 | 2.0 | 0.0 | -20.125 | -0.5 ];
+			input float in3 = [ 3.5 | 36.8125 | 1.0 | -8.25 | 2.0 | 0.0 | -0.5 | -20.125 ];
+			output vec4 out0 = [ vec4(1.0, 0.0, 3.5, 3.5) | vec4(0.0, 36.8125, 36.8125, 36.8125) | vec4(-0.5, -8.25, -8.25, 1.0) | vec4(-8.25, 2.0, 1.0, -8.25) | vec4(3.5, 3.5, 2.0, 2.0) | vec4(-20.125, 1.0, 0.0, 0.0) | vec4(36.8125, -20.125, -20.125, -0.5) | vec4(2.0, -0.5, -0.5, -20.125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_to_ivec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | 0.0 | -0.5 | -8.25 | 3.5 | -20.125 | 36.8125 | 2.0 ];
+			input float in1 = [ 0.0 | 36.8125 | -8.25 | 2.0 | 3.5 | 1.0 | -20.125 | -0.5 ];
+			input float in2 = [ 3.5 | 36.8125 | -8.25 | 1.0 | 2.0 | 0.0 | -20.125 | -0.5 ];
+			input float in3 = [ 3.5 | 36.8125 | 1.0 | -8.25 | 2.0 | 0.0 | -0.5 | -20.125 ];
+			output ivec4 out0 = [ ivec4(1, 0, 3, 3) | ivec4(0, 36, 36, 36) | ivec4(0, -8, -8, 1) | ivec4(-8, 2, 1, -8) | ivec4(3, 3, 2, 2) | ivec4(-20, 1, 0, 0) | ivec4(36, -20, -20, 0) | ivec4(2, 0, 0, -20) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_to_bvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | 0.0 | -0.5 | -8.25 | 3.5 | -20.125 | 36.8125 | 2.0 ];
+			input float in1 = [ 0.0 | 36.8125 | -8.25 | 2.0 | 3.5 | 1.0 | -20.125 | -0.5 ];
+			input float in2 = [ 3.5 | 36.8125 | -8.25 | 1.0 | 2.0 | 0.0 | -20.125 | -0.5 ];
+			input float in3 = [ 3.5 | 36.8125 | 1.0 | -8.25 | 2.0 | 0.0 | -0.5 | -20.125 ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_to_vec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | -66 | 2 | 5 | 8 | -192 | 255 | 1 | 0 | 11 ];
+			input int in1 = [ 2 | 5 | -66 | 11 | -192 | 8 | -12 | 1 | 255 | 0 ];
+			input int in2 = [ 11 | 255 | 5 | 8 | 2 | -192 | -12 | -66 | 1 | 0 ];
+			input int in3 = [ -192 | -66 | 8 | -12 | 1 | 2 | 0 | 255 | 5 | 11 ];
+			output vec4 out0 = [ vec4(-12.0, 2.0, 11.0, -192.0) | vec4(-66.0, 5.0, 255.0, -66.0) | vec4(2.0, -66.0, 5.0, 8.0) | vec4(5.0, 11.0, 8.0, -12.0) | vec4(8.0, -192.0, 2.0, 1.0) | vec4(-192.0, 8.0, -192.0, 2.0) | vec4(255.0, -12.0, -12.0, 0.0) | vec4(1.0, 1.0, -66.0, 255.0) | vec4(0.0, 255.0, 1.0, 5.0) | vec4(11.0, 0.0, 0.0, 11.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_to_ivec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | -66 | 2 | 5 | 8 | -192 | 255 | 1 | 0 | 11 ];
+			input int in1 = [ 2 | 5 | -66 | 11 | -192 | 8 | -12 | 1 | 255 | 0 ];
+			input int in2 = [ 11 | 255 | 5 | 8 | 2 | -192 | -12 | -66 | 1 | 0 ];
+			input int in3 = [ -192 | -66 | 8 | -12 | 1 | 2 | 0 | 255 | 5 | 11 ];
+			output ivec4 out0 = [ ivec4(-12, 2, 11, -192) | ivec4(-66, 5, 255, -66) | ivec4(2, -66, 5, 8) | ivec4(5, 11, 8, -12) | ivec4(8, -192, 2, 1) | ivec4(-192, 8, -192, 2) | ivec4(255, -12, -12, 0) | ivec4(1, 1, -66, 255) | ivec4(0, 255, 1, 5) | ivec4(11, 0, 0, 11) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_to_bvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | -66 | 2 | 5 | 8 | -192 | 255 | 1 | 0 | 11 ];
+			input int in1 = [ 2 | 5 | -66 | 11 | -192 | 8 | -12 | 1 | 255 | 0 ];
+			input int in2 = [ 11 | 255 | 5 | 8 | 2 | -192 | -12 | -66 | 1 | 0 ];
+			input int in3 = [ -192 | -66 | 8 | -12 | 1 | 2 | 0 | 255 | 5 | 11 ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, false) | bvec4(true, true, true, true) | bvec4(false, true, true, true) | bvec4(true, false, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_uint_to_vec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 193 | 3 | 255 | 8 | 10 | 9 | 2 | 12 | 0 | 45 ];
+			input uint in1 = [ 12 | 45 | 193 | 2 | 8 | 255 | 0 | 3 | 9 | 10 ];
+			input uint in2 = [ 9 | 8 | 12 | 2 | 255 | 45 | 3 | 0 | 193 | 10 ];
+			input uint in3 = [ 3 | 9 | 12 | 2 | 255 | 193 | 0 | 10 | 45 | 8 ];
+			output vec4 out0 = [ vec4(193.0, 12.0, 9.0, 3.0) | vec4(3.0, 45.0, 8.0, 9.0) | vec4(255.0, 193.0, 12.0, 12.0) | vec4(8.0, 2.0, 2.0, 2.0) | vec4(10.0, 8.0, 255.0, 255.0) | vec4(9.0, 255.0, 45.0, 193.0) | vec4(2.0, 0.0, 3.0, 0.0) | vec4(12.0, 3.0, 0.0, 10.0) | vec4(0.0, 9.0, 193.0, 45.0) | vec4(45.0, 10.0, 10.0, 8.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_uint_to_ivec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 193 | 3 | 255 | 8 | 10 | 9 | 2 | 12 | 0 | 45 ];
+			input uint in1 = [ 12 | 45 | 193 | 2 | 8 | 255 | 0 | 3 | 9 | 10 ];
+			input uint in2 = [ 9 | 8 | 12 | 2 | 255 | 45 | 3 | 0 | 193 | 10 ];
+			input uint in3 = [ 3 | 9 | 12 | 2 | 255 | 193 | 0 | 10 | 45 | 8 ];
+			output ivec4 out0 = [ ivec4(193, 12, 9, 3) | ivec4(3, 45, 8, 9) | ivec4(255, 193, 12, 12) | ivec4(8, 2, 2, 2) | ivec4(10, 8, 255, 255) | ivec4(9, 255, 45, 193) | ivec4(2, 0, 3, 0) | ivec4(12, 3, 0, 10) | ivec4(0, 9, 193, 45) | ivec4(45, 10, 10, 8) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_uint_to_bvec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 193 | 3 | 255 | 8 | 10 | 9 | 2 | 12 | 0 | 45 ];
+			input uint in1 = [ 12 | 45 | 193 | 2 | 8 | 255 | 0 | 3 | 9 | 10 ];
+			input uint in2 = [ 9 | 8 | 12 | 2 | 255 | 45 | 3 | 0 | 193 | 10 ];
+			input uint in3 = [ 3 | 9 | 12 | 2 | 255 | 193 | 0 | 10 | 45 | 8 ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, false, true, false) | bvec4(true, true, false, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_to_vec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ false | true ];
+			input bool in3 = [ false | true ];
+			output vec4 out0 = [ vec4(1.0, 1.0, 0.0, 0.0) | vec4(0.0, 0.0, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_to_ivec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ false | true ];
+			input bool in3 = [ false | true ];
+			output ivec4 out0 = [ ivec4(1, 1, 0, 0) | ivec4(0, 0, 1, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_to_bvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ false | true ];
+			input bool in3 = [ false | true ];
+			output bvec4 out0 = [ bvec4(true, true, false, false) | bvec4(false, false, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_to_vec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | false | true | false | false | true | true ];
+			input float in1 = [ 36.8125 | 0.0 | -8.25 | 1.0 | -0.5 | 0.0 | 2.0 | -20.125 | 3.5 | 1.0 ];
+			input int in2 = [ -66 | 2 | 255 | 11 | 1 | 8 | -192 | -12 | 0 | 5 ];
+			input bool in3 = [ true | true | false | false | true | true | false | true | false | false ];
+			output vec4 out0 = [ vec4(1.0, 36.8125, -66.0, 1.0) | vec4(1.0, 0.0, 2.0, 1.0) | vec4(0.0, -8.25, 255.0, 0.0) | vec4(0.0, 1.0, 11.0, 0.0) | vec4(0.0, -0.5, 1.0, 1.0) | vec4(1.0, 0.0, 8.0, 1.0) | vec4(0.0, 2.0, -192.0, 0.0) | vec4(0.0, -20.125, -12.0, 1.0) | vec4(1.0, 3.5, 0.0, 0.0) | vec4(1.0, 1.0, 5.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_to_ivec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | false | true | false | false | true | true ];
+			input float in1 = [ 36.8125 | 0.0 | -8.25 | 1.0 | -0.5 | 0.0 | 2.0 | -20.125 | 3.5 | 1.0 ];
+			input int in2 = [ -66 | 2 | 255 | 11 | 1 | 8 | -192 | -12 | 0 | 5 ];
+			input bool in3 = [ true | true | false | false | true | true | false | true | false | false ];
+			output ivec4 out0 = [ ivec4(1, 36, -66, 1) | ivec4(1, 0, 2, 1) | ivec4(0, -8, 255, 0) | ivec4(0, 1, 11, 0) | ivec4(0, 0, 1, 1) | ivec4(1, 0, 8, 1) | ivec4(0, 2, -192, 0) | ivec4(0, -20, -12, 1) | ivec4(1, 3, 0, 0) | ivec4(1, 1, 5, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_to_bvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | false | true | false | false | true | true ];
+			input float in1 = [ 36.8125 | 0.0 | -8.25 | 1.0 | -0.5 | 0.0 | 2.0 | -20.125 | 3.5 | 1.0 ];
+			input int in2 = [ -66 | 2 | 255 | 11 | 1 | 8 | -192 | -12 | 0 | 5 ];
+			input bool in3 = [ true | true | false | false | true | true | false | true | false | false ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, false, true, true) | bvec4(false, true, true, false) | bvec4(false, true, true, false) | bvec4(false, true, true, true) | bvec4(true, false, true, true) | bvec4(false, true, true, false) | bvec4(false, true, true, true) | bvec4(true, true, false, false) | bvec4(true, true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_to_vec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(-0.75, -0.0322580645161, 0.0, -2.0) | vec4(-0.5, -2.25, 0.0, 0.0) | vec4(-32.0, 64.0, -32.0, 64.0) | vec4(1.0, 1.25, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_to_ivec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, -2) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, 64) | ivec4(1, 1, 1, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_to_bvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) ];
+			output bvec4 out0 = [ bvec4(false, true, false, false) | bvec4(true, true, false, true) | bvec4(true, true, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec2_to_vec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) ];
+			input bvec2 in1 = [ bvec2(false, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(true, false) ];
+			output vec4 out0 = [ vec4(-0.75, -0.0322580645161, 0.0, 1.0) | vec4(-32.0, 64.0, 0.0, 0.0) | vec4(1.0, 1.25, 0.0, 0.0) | vec4(0.0, 0.5, 1.0, 1.0) | vec4(-0.5, -2.25, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec2_to_ivec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) ];
+			input bvec2 in1 = [ bvec2(false, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(true, false) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 1) | ivec4(-32, 64, 0, 0) | ivec4(1, 1, 0, 0) | ivec4(0, 0, 1, 1) | ivec4(0, -2, 1, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec2_to_bvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) ];
+			input bvec2 in1 = [ bvec2(false, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(true, false) ];
+			output bvec4 out0 = [ bvec4(true, true, false, true) | bvec4(true, true, false, false) | bvec4(true, true, false, false) | bvec4(false, true, true, true) | bvec4(true, true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_to_vec4
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, false, false) | bvec3(false, true, false) ];
+			input float in1 = [ -0.5 | 3.5 | 2.0 | 0.0 | -8.25 | 1.0 | 36.8125 | -20.125 ];
+			output vec4 out0 = [ vec4(1.0, 0.0, 0.0, -0.5) | vec4(0.0, 0.0, 0.0, 3.5) | vec4(0.0, 1.0, 0.0, 2.0) | vec4(1.0, 1.0, 1.0, 0.0) | vec4(0.0, 0.0, 0.0, -8.25) | vec4(0.0, 0.0, 0.0, 1.0) | vec4(1.0, 0.0, 0.0, 36.8125) | vec4(0.0, 1.0, 0.0, -20.125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_to_ivec4
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, false, false) | bvec3(false, true, false) ];
+			input float in1 = [ -0.5 | 3.5 | 2.0 | 0.0 | -8.25 | 1.0 | 36.8125 | -20.125 ];
+			output ivec4 out0 = [ ivec4(1, 0, 0, 0) | ivec4(0, 0, 0, 3) | ivec4(0, 1, 0, 2) | ivec4(1, 1, 1, 0) | ivec4(0, 0, 0, -8) | ivec4(0, 0, 0, 1) | ivec4(1, 0, 0, 36) | ivec4(0, 1, 0, -20) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_to_bvec4
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, false, false) | bvec3(false, true, false) ];
+			input float in1 = [ -0.5 | 3.5 | 2.0 | 0.0 | -8.25 | 1.0 | 36.8125 | -20.125 ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, true) | bvec4(true, true, true, false) | bvec4(false, false, false, true) | bvec4(false, false, false, true) | bvec4(true, false, false, true) | bvec4(false, true, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_to_vec4
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) ];
+			input float in1 = [ -0.5 | 0.0 | 3.5 | -20.125 | 2.0 | -8.25 | 1.0 | 36.8125 ];
+			output vec4 out0 = [ vec4(-32.0, 64.0, -51.0, -0.5) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.0) | vec4(1.0, 1.25, 1.125, 3.5) | vec4(-0.5, -2.25, -4.875, -20.125) | vec4(0.0, 0.5, 0.75, 2.0) | vec4(-0.5, -2.25, -4.875, -8.25) | vec4(0.0, 0.5, 0.75, 1.0) | vec4(1.0, 1.25, 1.125, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_to_ivec4
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) ];
+			input float in1 = [ -0.5 | 0.0 | 3.5 | -20.125 | 2.0 | -8.25 | 1.0 | 36.8125 ];
+			output ivec4 out0 = [ ivec4(-32, 64, -51, 0) | ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 3) | ivec4(0, -2, -4, -20) | ivec4(0, 0, 0, 2) | ivec4(0, -2, -4, -8) | ivec4(0, 0, 0, 1) | ivec4(1, 1, 1, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_to_bvec4
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) ];
+			input float in1 = [ -0.5 | 0.0 | 3.5 | -20.125 | 2.0 | -8.25 | 1.0 | 36.8125 ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) | bvec4(false, true, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2_int_to_vec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | 11 | 8 | 255 | 0 | 1 | -66 | 2 | -192 | 5 ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(0, 0) | ivec2(0, 0) ];
+			input int in2 = [ 1 | 11 | 2 | -66 | -192 | 0 | -12 | 255 | 5 | 8 ];
+			output vec4 out0 = [ vec4(-12.0, 0.0, -2.0, 1.0) | vec4(11.0, -32.0, 64.0, 11.0) | vec4(8.0, 0.0, 0.0, 2.0) | vec4(255.0, 0.0, -2.0, -66.0) | vec4(0.0, 1.0, 1.0, -192.0) | vec4(1.0, 0.0, 0.0, 0.0) | vec4(-66.0, -32.0, 64.0, -12.0) | vec4(2.0, 1.0, 1.0, 255.0) | vec4(-192.0, 0.0, 0.0, 5.0) | vec4(5.0, 0.0, 0.0, 8.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2_int_to_ivec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | 11 | 8 | 255 | 0 | 1 | -66 | 2 | -192 | 5 ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(0, 0) | ivec2(0, 0) ];
+			input int in2 = [ 1 | 11 | 2 | -66 | -192 | 0 | -12 | 255 | 5 | 8 ];
+			output ivec4 out0 = [ ivec4(-12, 0, -2, 1) | ivec4(11, -32, 64, 11) | ivec4(8, 0, 0, 2) | ivec4(255, 0, -2, -66) | ivec4(0, 1, 1, -192) | ivec4(1, 0, 0, 0) | ivec4(-66, -32, 64, -12) | ivec4(2, 1, 1, 255) | ivec4(-192, 0, 0, 5) | ivec4(5, 0, 0, 8) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2_int_to_bvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ -12 | 11 | 8 | 255 | 0 | 1 | -66 | 2 | -192 | 5 ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(0, 0) | ivec2(0, 0) ];
+			input int in2 = [ 1 | 11 | 2 | -66 | -192 | 0 | -12 | 255 | 5 | 8 ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(true, true, true, true) | bvec4(true, false, false, true) | bvec4(true, false, true, true) | bvec4(false, true, true, true) | bvec4(true, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, false, false, true) | bvec4(true, false, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_ivec2_to_vec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | false | false | true | true | true | false ];
+			input float in1 = [ 1.0 | 0.0 | 2.0 | 3.5 | -20.125 | -0.5 | 36.8125 | -8.25 ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, -2) | ivec2(0, 0) | ivec2(1, 1) ];
+			output vec4 out0 = [ vec4(1.0, 1.0, 1.0, 1.0) | vec4(0.0, 0.0, -32.0, 64.0) | vec4(0.0, 2.0, 0.0, 0.0) | vec4(0.0, 3.5, 0.0, 0.0) | vec4(1.0, -20.125, 0.0, -2.0) | vec4(1.0, -0.5, 0.0, -2.0) | vec4(1.0, 36.8125, 0.0, 0.0) | vec4(0.0, -8.25, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_ivec2_to_ivec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | false | false | true | true | true | false ];
+			input float in1 = [ 1.0 | 0.0 | 2.0 | 3.5 | -20.125 | -0.5 | 36.8125 | -8.25 ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, -2) | ivec2(0, 0) | ivec2(1, 1) ];
+			output ivec4 out0 = [ ivec4(1, 1, 1, 1) | ivec4(0, 0, -32, 64) | ivec4(0, 2, 0, 0) | ivec4(0, 3, 0, 0) | ivec4(1, -20, 0, -2) | ivec4(1, 0, 0, -2) | ivec4(1, 36, 0, 0) | ivec4(0, -8, 1, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_ivec2_to_bvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | false | false | true | true | true | false ];
+			input float in1 = [ 1.0 | 0.0 | 2.0 | 3.5 | -20.125 | -0.5 | 36.8125 | -8.25 ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, -2) | ivec2(0, 0) | ivec2(1, 1) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(false, false, true, true) | bvec4(false, true, false, false) | bvec4(false, true, false, false) | bvec4(true, true, false, true) | bvec4(true, true, false, true) | bvec4(true, true, false, false) | bvec4(false, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec3_to_vec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | -20.125 | -8.25 | -0.5 | 0.0 | 2.0 | 3.5 | 36.8125 ];
+			input uvec3 in1 = [ uvec3(0, 0, 0) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) ];
+			output vec4 out0 = [ vec4(1.0, 0.0, 0.0, 0.0) | vec4(-20.125, 0.0, 0.0, 0.0) | vec4(-8.25, 1.0, 1.0, 1.0) | vec4(-0.5, 0.0, 2.0, 4.0) | vec4(0.0, 0.0, 0.0, 0.0) | vec4(2.0, 1.0, 1.0, 1.0) | vec4(3.5, 0.0, 2.0, 4.0) | vec4(36.8125, 32.0, 64.0, 51.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec3_to_ivec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | -20.125 | -8.25 | -0.5 | 0.0 | 2.0 | 3.5 | 36.8125 ];
+			input uvec3 in1 = [ uvec3(0, 0, 0) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) ];
+			output ivec4 out0 = [ ivec4(1, 0, 0, 0) | ivec4(-20, 0, 0, 0) | ivec4(-8, 1, 1, 1) | ivec4(0, 0, 2, 4) | ivec4(0, 0, 0, 0) | ivec4(2, 1, 1, 1) | ivec4(3, 0, 2, 4) | ivec4(36, 32, 64, 51) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec3_to_bvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | -20.125 | -8.25 | -0.5 | 0.0 | 2.0 | 3.5 | 36.8125 ];
+			input uvec3 in1 = [ uvec3(0, 0, 0) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(0, 0, 0) | uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(32, 64, 51) ];
+			output bvec4 out0 = [ bvec4(true, false, false, false) | bvec4(true, false, false, false) | bvec4(true, true, true, true) | bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, false, true, true) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uvec2_bool_to_vec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | -192 | -66 | -12 | 0 | 2 | 11 | 8 | 255 | 5 ];
+			input uvec2 in1 = [ uvec2(0, 2) | uvec2(1, 1) | uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(32, 64) | uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 0) ];
+			input bool in2 = [ false | false | true | true | true | true | true | false | false | false ];
+			output vec4 out0 = [ vec4(1.0, 0.0, 2.0, 0.0) | vec4(-192.0, 1.0, 1.0, 0.0) | vec4(-66.0, 0.0, 0.0, 1.0) | vec4(-12.0, 0.0, 2.0, 1.0) | vec4(0.0, 32.0, 64.0, 1.0) | vec4(2.0, 0.0, 0.0, 1.0) | vec4(11.0, 32.0, 64.0, 1.0) | vec4(8.0, 0.0, 0.0, 0.0) | vec4(255.0, 1.0, 1.0, 0.0) | vec4(5.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uvec2_bool_to_ivec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | -192 | -66 | -12 | 0 | 2 | 11 | 8 | 255 | 5 ];
+			input uvec2 in1 = [ uvec2(0, 2) | uvec2(1, 1) | uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(32, 64) | uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 0) ];
+			input bool in2 = [ false | false | true | true | true | true | true | false | false | false ];
+			output ivec4 out0 = [ ivec4(1, 0, 2, 0) | ivec4(-192, 1, 1, 0) | ivec4(-66, 0, 0, 1) | ivec4(-12, 0, 2, 1) | ivec4(0, 32, 64, 1) | ivec4(2, 0, 0, 1) | ivec4(11, 32, 64, 1) | ivec4(8, 0, 0, 0) | ivec4(255, 1, 1, 0) | ivec4(5, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uvec2_bool_to_bvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | -192 | -66 | -12 | 0 | 2 | 11 | 8 | 255 | 5 ];
+			input uvec2 in1 = [ uvec2(0, 2) | uvec2(1, 1) | uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(32, 64) | uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 0) ];
+			input bool in2 = [ false | false | true | true | true | true | true | false | false | false ];
+			output bvec4 out0 = [ bvec4(true, false, true, false) | bvec4(true, true, true, false) | bvec4(true, false, false, true) | bvec4(true, false, true, true) | bvec4(false, true, true, true) | bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(true, false, false, false) | bvec4(true, true, true, false) | bvec4(true, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_vec2_to_uvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(32.0, 64.0) | vec2(0.75, 0.0322580645161) | vec2(0.0, 0.5) | vec2(0.5, 2.25) | vec2(1.0, 1.25) ];
+			input vec2 in1 = [ vec2(0.5, 2.25) | vec2(1.0, 1.25) | vec2(32.0, 64.0) | vec2(0.0, 0.5) | vec2(0.75, 0.0322580645161) ];
+			output uvec4 out0 = [ uvec4(32, 64, 0, 2) | uvec4(0, 0, 1, 1) | uvec4(0, 0, 32, 64) | uvec4(0, 2, 0, 0) | uvec4(1, 1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_bvec2_to_uvec4
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) | bvec2(false, false) ];
+			input bvec2 in1 = [ bvec2(true, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) ];
+			output uvec4 out0 = [ uvec4(1, 0, 1, 1) | uvec4(0, 1, 0, 0) | uvec4(1, 1, 1, 0) | uvec4(0, 0, 0, 1) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_to_uvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 36.8125 | 0.0 | 20.125 | 1.0 | 0.5 | 8.25 | 3.5 ];
+			input float in1 = [ 1.0 | 8.25 | 2.0 | 20.125 | 36.8125 | 0.0 | 0.5 | 3.5 ];
+			input float in2 = [ 0.0 | 8.25 | 2.0 | 1.0 | 36.8125 | 20.125 | 0.5 | 3.5 ];
+			input float in3 = [ 1.0 | 8.25 | 0.0 | 2.0 | 20.125 | 3.5 | 0.5 | 36.8125 ];
+			output uvec4 out0 = [ uvec4(2, 1, 0, 1) | uvec4(36, 8, 8, 8) | uvec4(0, 2, 2, 0) | uvec4(20, 20, 1, 2) | uvec4(1, 36, 36, 20) | uvec4(0, 0, 20, 3) | uvec4(8, 0, 0, 0) | uvec4(3, 3, 3, 36) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_to_uvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 192 | 2 | 12 | 11 | 0 | 8 | 5 | 66 | 1 | 255 ];
+			input int in1 = [ 66 | 12 | 5 | 1 | 0 | 192 | 8 | 255 | 11 | 2 ];
+			input int in2 = [ 192 | 5 | 1 | 66 | 255 | 11 | 8 | 12 | 2 | 0 ];
+			input int in3 = [ 255 | 5 | 11 | 12 | 2 | 1 | 66 | 0 | 8 | 192 ];
+			output uvec4 out0 = [ uvec4(192, 66, 192, 255) | uvec4(2, 12, 5, 5) | uvec4(12, 5, 1, 11) | uvec4(11, 1, 66, 12) | uvec4(0, 0, 255, 2) | uvec4(8, 192, 11, 1) | uvec4(5, 8, 8, 66) | uvec4(66, 255, 12, 0) | uvec4(1, 11, 2, 8) | uvec4(255, 2, 0, 192) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_uint_to_uvec4
+		version 310 es
+		values
+		{
+			input uint in0 = [ 255 | 8 | 3 | 193 | 45 | 2 | 0 | 12 | 9 | 10 ];
+			input uint in1 = [ 255 | 45 | 0 | 12 | 2 | 10 | 8 | 9 | 193 | 3 ];
+			input uint in2 = [ 3 | 0 | 2 | 9 | 12 | 10 | 255 | 45 | 193 | 8 ];
+			input uint in3 = [ 2 | 255 | 10 | 193 | 8 | 12 | 3 | 9 | 0 | 45 ];
+			output uvec4 out0 = [ uvec4(255, 255, 3, 2) | uvec4(8, 45, 0, 255) | uvec4(3, 0, 2, 10) | uvec4(193, 12, 9, 193) | uvec4(45, 2, 12, 8) | uvec4(2, 10, 10, 12) | uvec4(0, 8, 255, 3) | uvec4(12, 9, 45, 9) | uvec4(9, 193, 193, 0) | uvec4(10, 3, 8, 45) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_to_uvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true ];
+			input bool in1 = [ false | true ];
+			input bool in2 = [ true | false ];
+			input bool in3 = [ true | false ];
+			output uvec4 out0 = [ uvec4(0, 0, 1, 1) | uvec4(1, 1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_to_uvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | false | true | false | true | true | true | false | false ];
+			input float in1 = [ 20.125 | 0.0 | 1.0 | 3.5 | 1.0 | 0.0 | 0.5 | 8.25 | 2.0 | 36.8125 ];
+			input int in2 = [ 66 | 192 | 1 | 2 | 5 | 11 | 8 | 12 | 255 | 0 ];
+			input bool in3 = [ true | true | true | true | false | true | false | false | false | false ];
+			output uvec4 out0 = [ uvec4(1, 20, 66, 1) | uvec4(0, 0, 192, 1) | uvec4(0, 1, 1, 1) | uvec4(1, 3, 2, 1) | uvec4(0, 1, 5, 0) | uvec4(1, 0, 11, 1) | uvec4(1, 0, 8, 0) | uvec4(1, 8, 12, 0) | uvec4(0, 2, 255, 0) | uvec4(0, 36, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_to_uvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.5, 2.25) | vec2(1.0, 1.25) | vec2(32.0, 64.0) | vec2(0.75, 0.0322580645161) | vec2(0.0, 0.5) ];
+			input ivec2 in1 = [ ivec2(1, 1) | ivec2(0, 2) | ivec2(32, 64) | ivec2(0, 0) | ivec2(0, 0) ];
+			output uvec4 out0 = [ uvec4(0, 2, 1, 1) | uvec4(1, 1, 0, 2) | uvec4(32, 64, 32, 64) | uvec4(0, 0, 0, 0) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec2_to_uvec4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(32.0, 64.0) | vec2(0.75, 0.0322580645161) | vec2(0.5, 2.25) | vec2(0.0, 0.5) | vec2(1.0, 1.25) ];
+			input bvec2 in1 = [ bvec2(false, false) | bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(true, true) ];
+			output uvec4 out0 = [ uvec4(32, 64, 0, 0) | uvec4(0, 0, 0, 0) | uvec4(0, 2, 1, 0) | uvec4(0, 0, 0, 1) | uvec4(1, 1, 1, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_to_uvec4
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(true, true, true) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, false, false) | bvec3(false, false, false) ];
+			input float in1 = [ 2.0 | 0.0 | 36.8125 | 0.5 | 1.0 | 8.25 | 3.5 | 20.125 ];
+			output uvec4 out0 = [ uvec4(1, 0, 0, 2) | uvec4(1, 1, 1, 0) | uvec4(0, 1, 0, 36) | uvec4(0, 0, 0, 0) | uvec4(0, 0, 0, 1) | uvec4(0, 1, 0, 8) | uvec4(1, 0, 0, 3) | uvec4(0, 0, 0, 20) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_to_uvec4
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.5, 2.25, 4.875) | vec3(1.0, 1.25, 1.125) | vec3(0.0, 0.5, 0.75) | vec3(0.5, 2.25, 4.875) | vec3(32.0, 64.0, 51.0) | vec3(1.0, 1.25, 1.125) | vec3(0.75, 0.0322580645161, 0.0526315789474) | vec3(0.0, 0.5, 0.75) ];
+			input float in1 = [ 8.25 | 1.0 | 0.0 | 36.8125 | 2.0 | 0.5 | 20.125 | 3.5 ];
+			output uvec4 out0 = [ uvec4(0, 2, 4, 8) | uvec4(1, 1, 1, 1) | uvec4(0, 0, 0, 0) | uvec4(0, 2, 4, 36) | uvec4(32, 64, 51, 2) | uvec4(1, 1, 1, 0) | uvec4(0, 0, 0, 20) | uvec4(0, 0, 0, 3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2_int_to_uvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 8 | 1 | 11 | 192 | 255 | 12 | 66 | 2 | 0 | 5 ];
+			input ivec2 in1 = [ ivec2(1, 1) | ivec2(0, 0) | ivec2(1, 1) | ivec2(32, 64) | ivec2(0, 2) | ivec2(0, 2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(32, 64) | ivec2(0, 0) ];
+			input int in2 = [ 2 | 192 | 12 | 0 | 8 | 1 | 66 | 255 | 11 | 5 ];
+			output uvec4 out0 = [ uvec4(8, 1, 1, 2) | uvec4(1, 0, 0, 192) | uvec4(11, 1, 1, 12) | uvec4(192, 32, 64, 0) | uvec4(255, 0, 2, 8) | uvec4(12, 0, 2, 1) | uvec4(66, 0, 0, 66) | uvec4(2, 0, 0, 255) | uvec4(0, 32, 64, 11) | uvec4(5, 0, 0, 5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_ivec2_to_uvec4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true | false | false | true ];
+			input float in1 = [ 8.25 | 0.5 | 2.0 | 20.125 | 0.0 | 36.8125 | 3.5 | 1.0 ];
+			input ivec2 in2 = [ ivec2(32, 64) | ivec2(1, 1) | ivec2(0, 2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, 2) | ivec2(1, 1) | ivec2(0, 0) ];
+			output uvec4 out0 = [ uvec4(1, 8, 32, 64) | uvec4(1, 0, 1, 1) | uvec4(0, 2, 0, 2) | uvec4(0, 20, 0, 0) | uvec4(1, 0, 0, 0) | uvec4(0, 36, 0, 2) | uvec4(0, 3, 1, 1) | uvec4(1, 1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec3_to_uvec4
+		version 310 es
+		values
+		{
+			input float in0 = [ 8.25 | 20.125 | 1.0 | 0.5 | 3.5 | 2.0 | 36.8125 | 0.0 ];
+			input uvec3 in1 = [ uvec3(0, 0, 0) | uvec3(0, 0, 0) | uvec3(0, 2, 4) | uvec3(32, 64, 51) | uvec3(0, 2, 4) | uvec3(1, 1, 1) | uvec3(1, 1, 1) | uvec3(0, 0, 0) ];
+			output uvec4 out0 = [ uvec4(8, 0, 0, 0) | uvec4(20, 0, 0, 0) | uvec4(1, 0, 2, 4) | uvec4(0, 32, 64, 51) | uvec4(3, 0, 2, 4) | uvec4(2, 1, 1, 1) | uvec4(36, 1, 1, 1) | uvec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uvec2_bool_to_uvec4
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | 1 | 11 | 66 | 192 | 12 | 8 | 255 | 0 | 5 ];
+			input uvec2 in1 = [ uvec2(1, 1) | uvec2(0, 0) | uvec2(0, 0) | uvec2(0, 2) | uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(1, 1) | uvec2(32, 64) | uvec2(0, 0) ];
+			input bool in2 = [ true | false | false | false | false | true | true | true | false | true ];
+			output uvec4 out0 = [ uvec4(2, 1, 1, 1) | uvec4(1, 0, 0, 0) | uvec4(11, 0, 0, 0) | uvec4(66, 0, 2, 0) | uvec4(192, 0, 0, 0) | uvec4(12, 0, 2, 1) | uvec4(8, 32, 64, 1) | uvec4(255, 1, 1, 1) | uvec4(0, 32, 64, 0) | uvec4(5, 0, 0, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_to_vec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | 1.0 | 3.5 | -8.25 | 36.8125 | 0.0 | 2.0 | -20.125 ];
+			input float in1 = [ 2.0 | -20.125 | 3.5 | 36.8125 | -8.25 | 1.0 | -0.5 | 0.0 ];
+			input float in2 = [ 1.0 | 3.5 | 2.0 | -8.25 | -20.125 | -0.5 | 36.8125 | 0.0 ];
+			output vec3 out0 = [ vec3(-0.5, 2.0, 1.0) | vec3(1.0, -20.125, 3.5) | vec3(3.5, 3.5, 2.0) | vec3(-8.25, 36.8125, -8.25) | vec3(36.8125, -8.25, -20.125) | vec3(0.0, 1.0, -0.5) | vec3(2.0, -0.5, 36.8125) | vec3(-20.125, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_to_ivec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | 1.0 | 3.5 | -8.25 | 36.8125 | 0.0 | 2.0 | -20.125 ];
+			input float in1 = [ 2.0 | -20.125 | 3.5 | 36.8125 | -8.25 | 1.0 | -0.5 | 0.0 ];
+			input float in2 = [ 1.0 | 3.5 | 2.0 | -8.25 | -20.125 | -0.5 | 36.8125 | 0.0 ];
+			output ivec3 out0 = [ ivec3(0, 2, 1) | ivec3(1, -20, 3) | ivec3(3, 3, 2) | ivec3(-8, 36, -8) | ivec3(36, -8, -20) | ivec3(0, 1, 0) | ivec3(2, 0, 36) | ivec3(-20, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_to_bvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | 1.0 | 3.5 | -8.25 | 36.8125 | 0.0 | 2.0 | -20.125 ];
+			input float in1 = [ 2.0 | -20.125 | 3.5 | 36.8125 | -8.25 | 1.0 | -0.5 | 0.0 ];
+			input float in2 = [ 1.0 | 3.5 | 2.0 | -8.25 | -20.125 | -0.5 | 36.8125 | 0.0 ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(true, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_to_vec3
+		version 310 es
+		values
+		{
+			input int in0 = [ -192 | 5 | -12 | 0 | 11 | 8 | 1 | -66 | 255 | 2 ];
+			input int in1 = [ 5 | 1 | 8 | 0 | 2 | -192 | -12 | 255 | -66 | 11 ];
+			input int in2 = [ -192 | 1 | 2 | 5 | -12 | 8 | 11 | 0 | 255 | -66 ];
+			output vec3 out0 = [ vec3(-192.0, 5.0, -192.0) | vec3(5.0, 1.0, 1.0) | vec3(-12.0, 8.0, 2.0) | vec3(0.0, 0.0, 5.0) | vec3(11.0, 2.0, -12.0) | vec3(8.0, -192.0, 8.0) | vec3(1.0, -12.0, 11.0) | vec3(-66.0, 255.0, 0.0) | vec3(255.0, -66.0, 255.0) | vec3(2.0, 11.0, -66.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_to_ivec3
+		version 310 es
+		values
+		{
+			input int in0 = [ -192 | 5 | -12 | 0 | 11 | 8 | 1 | -66 | 255 | 2 ];
+			input int in1 = [ 5 | 1 | 8 | 0 | 2 | -192 | -12 | 255 | -66 | 11 ];
+			input int in2 = [ -192 | 1 | 2 | 5 | -12 | 8 | 11 | 0 | 255 | -66 ];
+			output ivec3 out0 = [ ivec3(-192, 5, -192) | ivec3(5, 1, 1) | ivec3(-12, 8, 2) | ivec3(0, 0, 5) | ivec3(11, 2, -12) | ivec3(8, -192, 8) | ivec3(1, -12, 11) | ivec3(-66, 255, 0) | ivec3(255, -66, 255) | ivec3(2, 11, -66) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_to_bvec3
+		version 310 es
+		values
+		{
+			input int in0 = [ -192 | 5 | -12 | 0 | 11 | 8 | 1 | -66 | 255 | 2 ];
+			input int in1 = [ 5 | 1 | 8 | 0 | 2 | -192 | -12 | 255 | -66 | 11 ];
+			input int in2 = [ -192 | 1 | 2 | 5 | -12 | 8 | 11 | 0 | 255 | -66 ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, false) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_to_vec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 8 | 45 | 2 | 3 | 255 | 193 | 12 | 0 | 9 | 10 ];
+			input uint in1 = [ 193 | 2 | 9 | 8 | 0 | 255 | 45 | 3 | 10 | 12 ];
+			input uint in2 = [ 12 | 2 | 193 | 255 | 8 | 10 | 45 | 0 | 3 | 9 ];
+			output vec3 out0 = [ vec3(8.0, 193.0, 12.0) | vec3(45.0, 2.0, 2.0) | vec3(2.0, 9.0, 193.0) | vec3(3.0, 8.0, 255.0) | vec3(255.0, 0.0, 8.0) | vec3(193.0, 255.0, 10.0) | vec3(12.0, 45.0, 45.0) | vec3(0.0, 3.0, 0.0) | vec3(9.0, 10.0, 3.0) | vec3(10.0, 12.0, 9.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_to_ivec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 8 | 45 | 2 | 3 | 255 | 193 | 12 | 0 | 9 | 10 ];
+			input uint in1 = [ 193 | 2 | 9 | 8 | 0 | 255 | 45 | 3 | 10 | 12 ];
+			input uint in2 = [ 12 | 2 | 193 | 255 | 8 | 10 | 45 | 0 | 3 | 9 ];
+			output ivec3 out0 = [ ivec3(8, 193, 12) | ivec3(45, 2, 2) | ivec3(2, 9, 193) | ivec3(3, 8, 255) | ivec3(255, 0, 8) | ivec3(193, 255, 10) | ivec3(12, 45, 45) | ivec3(0, 3, 0) | ivec3(9, 10, 3) | ivec3(10, 12, 9) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_to_bvec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 8 | 45 | 2 | 3 | 255 | 193 | 12 | 0 | 9 | 10 ];
+			input uint in1 = [ 193 | 2 | 9 | 8 | 0 | 255 | 45 | 3 | 10 | 12 ];
+			input uint in2 = [ 12 | 2 | 193 | 255 | 8 | 10 | 45 | 0 | 3 | 9 ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_to_vec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ true | false ];
+			output vec3 out0 = [ vec3(1.0, 1.0, 1.0) | vec3(0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_to_ivec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ true | false ];
+			output ivec3 out0 = [ ivec3(1, 1, 1) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_to_bvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ true | false ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_to_vec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true | false | true | false | false | true ];
+			input float in1 = [ 0.0 | 36.8125 | 0.0 | -8.25 | 1.0 | 3.5 | 1.0 | -0.5 | -20.125 | 2.0 ];
+			input int in2 = [ 8 | -192 | -66 | 2 | 1 | -12 | 11 | 255 | 5 | 0 ];
+			output vec3 out0 = [ vec3(1.0, 0.0, 8.0) | vec3(1.0, 36.8125, -192.0) | vec3(0.0, 0.0, -66.0) | vec3(0.0, -8.25, 2.0) | vec3(1.0, 1.0, 1.0) | vec3(0.0, 3.5, -12.0) | vec3(1.0, 1.0, 11.0) | vec3(0.0, -0.5, 255.0) | vec3(0.0, -20.125, 5.0) | vec3(1.0, 2.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_to_ivec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true | false | true | false | false | true ];
+			input float in1 = [ 0.0 | 36.8125 | 0.0 | -8.25 | 1.0 | 3.5 | 1.0 | -0.5 | -20.125 | 2.0 ];
+			input int in2 = [ 8 | -192 | -66 | 2 | 1 | -12 | 11 | 255 | 5 | 0 ];
+			output ivec3 out0 = [ ivec3(1, 0, 8) | ivec3(1, 36, -192) | ivec3(0, 0, -66) | ivec3(0, -8, 2) | ivec3(1, 1, 1) | ivec3(0, 3, -12) | ivec3(1, 1, 11) | ivec3(0, 0, 255) | ivec3(0, -20, 5) | ivec3(1, 2, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_to_bvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true | false | true | false | false | true ];
+			input float in1 = [ 0.0 | 36.8125 | 0.0 | -8.25 | 1.0 | 3.5 | 1.0 | -0.5 | -20.125 | 2.0 ];
+			input int in2 = [ 8 | -192 | -66 | 2 | 1 | -12 | 11 | 255 | 5 | 0 ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(true, true, true) | bvec3(false, true, true) | bvec3(false, true, true) | bvec3(true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bool_to_vec3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) ];
+			input bool in1 = [ false | true | true | true | false ];
+			output vec3 out0 = [ vec3(1.0, 1.25, 0.0) | vec3(-0.75, -0.0322580645161, 1.0) | vec3(-32.0, 64.0, 1.0) | vec3(-0.5, -2.25, 1.0) | vec3(0.0, 0.5, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bool_to_ivec3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) ];
+			input bool in1 = [ false | true | true | true | false ];
+			output ivec3 out0 = [ ivec3(1, 1, 0) | ivec3(0, 0, 1) | ivec3(-32, 64, 1) | ivec3(0, -2, 1) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bool_to_bvec3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) ];
+			input bool in1 = [ false | true | true | true | false ];
+			output bvec3 out0 = [ bvec3(true, true, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_float_to_vec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, true) | bvec2(false, true) | bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+			input float in1 = [ -20.125 | 2.0 | 36.8125 | 1.0 | 3.5 | 0.0 | -8.25 | -0.5 ];
+			output vec3 out0 = [ vec3(1.0, 0.0, -20.125) | vec3(0.0, 1.0, 2.0) | vec3(0.0, 1.0, 36.8125) | vec3(1.0, 0.0, 1.0) | vec3(0.0, 0.0, 3.5) | vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, -8.25) | vec3(0.0, 0.0, -0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_float_to_ivec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, true) | bvec2(false, true) | bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+			input float in1 = [ -20.125 | 2.0 | 36.8125 | 1.0 | 3.5 | 0.0 | -8.25 | -0.5 ];
+			output ivec3 out0 = [ ivec3(1, 0, -20) | ivec3(0, 1, 2) | ivec3(0, 1, 36) | ivec3(1, 0, 1) | ivec3(0, 0, 3) | ivec3(0, 0, 0) | ivec3(1, 1, -8) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_float_to_bvec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, true) | bvec2(false, true) | bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+			input float in1 = [ -20.125 | 2.0 | 36.8125 | 1.0 | 3.5 | 0.0 | -8.25 | -0.5 ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, true, true) | bvec3(false, true, true) | bvec3(true, false, true) | bvec3(false, false, true) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_int_to_vec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input int in1 = [ 1 | -66 | 255 | 8 | -192 | 2 | 5 | 11 | -12 | 0 ];
+			output vec3 out0 = [ vec3(1.0, 1.0, 1.0) | vec3(0.0, 0.0, -66.0) | vec3(0.0, 0.0, 255.0) | vec3(1.0, 0.0, 8.0) | vec3(0.0, 0.0, -192.0) | vec3(0.0, 1.0, 2.0) | vec3(1.0, 0.0, 5.0) | vec3(0.0, 1.0, 11.0) | vec3(0.0, 0.0, -12.0) | vec3(1.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_int_to_ivec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input int in1 = [ 1 | -66 | 255 | 8 | -192 | 2 | 5 | 11 | -12 | 0 ];
+			output ivec3 out0 = [ ivec3(1, 1, 1) | ivec3(0, 0, -66) | ivec3(0, 0, 255) | ivec3(1, 0, 8) | ivec3(0, 0, -192) | ivec3(0, 1, 2) | ivec3(1, 0, 5) | ivec3(0, 1, 11) | ivec3(0, 0, -12) | ivec3(1, 1, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_int_to_bvec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) ];
+			input int in1 = [ 1 | -66 | 255 | 8 | -192 | 2 | 5 | 11 | -12 | 0 ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, true) | bvec3(false, false, true) | bvec3(true, false, true) | bvec3(false, false, true) | bvec3(false, true, true) | bvec3(true, false, true) | bvec3(false, true, true) | bvec3(false, false, true) | bvec3(true, true, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_ivec2_to_vec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(-32, 64) ];
+			output vec3 out0 = [ vec3(1.0, 0.0, -2.0) | vec3(1.0, 0.0, 0.0) | vec3(0.0, 0.0, 0.0) | vec3(0.0, 1.0, 1.0) | vec3(1.0, -32.0, 64.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_ivec2_to_ivec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(-32, 64) ];
+			output ivec3 out0 = [ ivec3(1, 0, -2) | ivec3(1, 0, 0) | ivec3(0, 0, 0) | ivec3(0, 1, 1) | ivec3(1, -32, 64) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_ivec2_to_bvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(-32, 64) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec2_to_vec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -20.125 | 36.8125 | -8.25 | 2.0 | -0.5 | 0.0 | 3.5 | 1.0 ];
+			input uvec2 in1 = [ uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(0, 2) | uvec2(0, 0) | uvec2(1, 1) | uvec2(1, 1) ];
+			output vec3 out0 = [ vec3(-20.125, 0.0, 0.0) | vec3(36.8125, 0.0, 2.0) | vec3(-8.25, 32.0, 64.0) | vec3(2.0, 0.0, 0.0) | vec3(-0.5, 0.0, 2.0) | vec3(0.0, 0.0, 0.0) | vec3(3.5, 1.0, 1.0) | vec3(1.0, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec2_to_ivec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -20.125 | 36.8125 | -8.25 | 2.0 | -0.5 | 0.0 | 3.5 | 1.0 ];
+			input uvec2 in1 = [ uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(0, 2) | uvec2(0, 0) | uvec2(1, 1) | uvec2(1, 1) ];
+			output ivec3 out0 = [ ivec3(-20, 0, 0) | ivec3(36, 0, 2) | ivec3(-8, 32, 64) | ivec3(2, 0, 0) | ivec3(0, 0, 2) | ivec3(0, 0, 0) | ivec3(3, 1, 1) | ivec3(1, 1, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec2_to_bvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ -20.125 | 36.8125 | -8.25 | 2.0 | -0.5 | 0.0 | 3.5 | 1.0 ];
+			input uvec2 in1 = [ uvec2(0, 0) | uvec2(0, 2) | uvec2(32, 64) | uvec2(0, 0) | uvec2(0, 2) | uvec2(0, 0) | uvec2(1, 1) | uvec2(1, 1) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(true, false, false) | bvec3(true, false, true) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_to_uvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 8.25 | 20.125 | 2.0 | 3.5 | 0.5 | 36.8125 | 1.0 | 0.0 ];
+			input float in1 = [ 1.0 | 0.0 | 3.5 | 36.8125 | 8.25 | 2.0 | 0.5 | 20.125 ];
+			input float in2 = [ 20.125 | 0.5 | 8.25 | 36.8125 | 1.0 | 0.0 | 3.5 | 2.0 ];
+			output uvec3 out0 = [ uvec3(8, 1, 20) | uvec3(20, 0, 0) | uvec3(2, 3, 8) | uvec3(3, 36, 36) | uvec3(0, 8, 1) | uvec3(36, 2, 0) | uvec3(1, 0, 3) | uvec3(0, 20, 2) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_to_uvec3
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 255 | 192 | 2 | 5 | 12 | 0 | 11 | 8 | 66 ];
+			input int in1 = [ 192 | 66 | 5 | 8 | 11 | 1 | 0 | 255 | 12 | 2 ];
+			input int in2 = [ 192 | 5 | 1 | 11 | 66 | 8 | 12 | 0 | 2 | 255 ];
+			output uvec3 out0 = [ uvec3(1, 192, 192) | uvec3(255, 66, 5) | uvec3(192, 5, 1) | uvec3(2, 8, 11) | uvec3(5, 11, 66) | uvec3(12, 1, 8) | uvec3(0, 0, 12) | uvec3(11, 255, 0) | uvec3(8, 12, 2) | uvec3(66, 2, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_to_uvec3
+		version 310 es
+		values
+		{
+			input uint in0 = [ 193 | 9 | 45 | 255 | 2 | 0 | 10 | 8 | 12 | 3 ];
+			input uint in1 = [ 3 | 45 | 2 | 9 | 10 | 0 | 8 | 12 | 255 | 193 ];
+			input uint in2 = [ 2 | 3 | 9 | 10 | 255 | 8 | 12 | 0 | 193 | 45 ];
+			output uvec3 out0 = [ uvec3(193, 3, 2) | uvec3(9, 45, 3) | uvec3(45, 2, 9) | uvec3(255, 9, 10) | uvec3(2, 10, 255) | uvec3(0, 0, 8) | uvec3(10, 8, 12) | uvec3(8, 12, 0) | uvec3(12, 255, 193) | uvec3(3, 193, 45) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_to_uvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true ];
+			input bool in1 = [ false | true ];
+			input bool in2 = [ true | false ];
+			output uvec3 out0 = [ uvec3(0, 0, 1) | uvec3(1, 1, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_to_uvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | true | false | false | true | false | true | true | false ];
+			input float in1 = [ 36.8125 | 20.125 | 1.0 | 0.0 | 3.5 | 1.0 | 2.0 | 0.5 | 0.0 | 8.25 ];
+			input int in2 = [ 1 | 0 | 8 | 66 | 2 | 11 | 192 | 5 | 12 | 255 ];
+			output uvec3 out0 = [ uvec3(1, 36, 1) | uvec3(0, 20, 0) | uvec3(1, 1, 8) | uvec3(0, 0, 66) | uvec3(0, 3, 2) | uvec3(1, 1, 11) | uvec3(0, 2, 192) | uvec3(1, 0, 5) | uvec3(1, 0, 12) | uvec3(0, 8, 255) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bool_to_uvec3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(32.0, 64.0) | vec2(0.5, 2.25) | vec2(1.0, 1.25) | vec2(0.75, 0.0322580645161) ];
+			input bool in1 = [ false | false | true | true | true ];
+			output uvec3 out0 = [ uvec3(0, 0, 0) | uvec3(32, 64, 0) | uvec3(0, 2, 1) | uvec3(1, 1, 1) | uvec3(0, 0, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_float_to_uvec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(false, false) ];
+			input float in1 = [ 8.25 | 36.8125 | 20.125 | 2.0 | 0.0 | 1.0 | 0.5 | 3.5 ];
+			output uvec3 out0 = [ uvec3(1, 1, 8) | uvec3(1, 0, 36) | uvec3(0, 1, 20) | uvec3(0, 0, 2) | uvec3(1, 0, 0) | uvec3(0, 1, 1) | uvec3(0, 0, 0) | uvec3(0, 0, 3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_int_to_uvec3
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, true) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, false) ];
+			input int in1 = [ 255 | 1 | 2 | 5 | 0 | 11 | 192 | 12 | 8 | 66 ];
+			output uvec3 out0 = [ uvec3(1, 1, 255) | uvec3(0, 1, 1) | uvec3(0, 0, 2) | uvec3(1, 1, 5) | uvec3(0, 0, 0) | uvec3(1, 0, 11) | uvec3(0, 0, 192) | uvec3(0, 0, 12) | uvec3(0, 1, 8) | uvec3(1, 0, 66) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_ivec2_to_uvec3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | true | true | false ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, 2) | ivec2(1, 1) | ivec2(0, 0) | ivec2(32, 64) ];
+			output uvec3 out0 = [ uvec3(1, 0, 0) | uvec3(0, 0, 2) | uvec3(1, 1, 1) | uvec3(1, 0, 0) | uvec3(0, 32, 64) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec2_to_uvec3
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 8.25 | 20.125 | 3.5 | 0.0 | 0.5 | 36.8125 | 1.0 ];
+			input uvec2 in1 = [ uvec2(0, 2) | uvec2(1, 1) | uvec2(32, 64) | uvec2(0, 0) | uvec2(0, 2) | uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 0) ];
+			output uvec3 out0 = [ uvec3(2, 0, 2) | uvec3(8, 1, 1) | uvec3(20, 32, 64) | uvec3(3, 0, 0) | uvec3(0, 0, 2) | uvec3(0, 0, 0) | uvec3(36, 1, 1) | uvec3(1, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_to_vec2
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | -20.125 | 1.0 | 2.0 | 3.5 | 36.8125 | -8.25 | 0.0 ];
+			input float in1 = [ 1.0 | -20.125 | 0.0 | 3.5 | -8.25 | 36.8125 | -0.5 | 2.0 ];
+			output vec2 out0 = [ vec2(-0.5, 1.0) | vec2(-20.125, -20.125) | vec2(1.0, 0.0) | vec2(2.0, 3.5) | vec2(3.5, -8.25) | vec2(36.8125, 36.8125) | vec2(-8.25, -0.5) | vec2(0.0, 2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_to_ivec2
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | -20.125 | 1.0 | 2.0 | 3.5 | 36.8125 | -8.25 | 0.0 ];
+			input float in1 = [ 1.0 | -20.125 | 0.0 | 3.5 | -8.25 | 36.8125 | -0.5 | 2.0 ];
+			output ivec2 out0 = [ ivec2(0, 1) | ivec2(-20, -20) | ivec2(1, 0) | ivec2(2, 3) | ivec2(3, -8) | ivec2(36, 36) | ivec2(-8, 0) | ivec2(0, 2) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_to_bvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ -0.5 | -20.125 | 1.0 | 2.0 | 3.5 | 36.8125 | -8.25 | 0.0 ];
+			input float in1 = [ 1.0 | -20.125 | 0.0 | 3.5 | -8.25 | 36.8125 | -0.5 | 2.0 ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(false, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_to_vec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | -66 | 0 | 5 | -12 | 8 | -192 | 1 | 11 | 255 ];
+			input int in1 = [ -192 | 8 | 1 | 0 | 5 | -66 | 2 | 255 | 11 | -12 ];
+			output vec2 out0 = [ vec2(2.0, -192.0) | vec2(-66.0, 8.0) | vec2(0.0, 1.0) | vec2(5.0, 0.0) | vec2(-12.0, 5.0) | vec2(8.0, -66.0) | vec2(-192.0, 2.0) | vec2(1.0, 255.0) | vec2(11.0, 11.0) | vec2(255.0, -12.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_to_ivec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | -66 | 0 | 5 | -12 | 8 | -192 | 1 | 11 | 255 ];
+			input int in1 = [ -192 | 8 | 1 | 0 | 5 | -66 | 2 | 255 | 11 | -12 ];
+			output ivec2 out0 = [ ivec2(2, -192) | ivec2(-66, 8) | ivec2(0, 1) | ivec2(5, 0) | ivec2(-12, 5) | ivec2(8, -66) | ivec2(-192, 2) | ivec2(1, 255) | ivec2(11, 11) | ivec2(255, -12) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_to_bvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | -66 | 0 | 5 | -12 | 8 | -192 | 1 | 11 | 255 ];
+			input int in1 = [ -192 | 8 | 1 | 0 | 5 | -66 | 2 | 255 | 11 | -12 ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, true) | bvec2(false, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_to_vec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 9 | 12 | 0 | 255 | 8 | 45 | 3 | 2 | 10 | 193 ];
+			input uint in1 = [ 8 | 9 | 45 | 2 | 12 | 193 | 255 | 0 | 3 | 10 ];
+			output vec2 out0 = [ vec2(9.0, 8.0) | vec2(12.0, 9.0) | vec2(0.0, 45.0) | vec2(255.0, 2.0) | vec2(8.0, 12.0) | vec2(45.0, 193.0) | vec2(3.0, 255.0) | vec2(2.0, 0.0) | vec2(10.0, 3.0) | vec2(193.0, 10.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_to_ivec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 9 | 12 | 0 | 255 | 8 | 45 | 3 | 2 | 10 | 193 ];
+			input uint in1 = [ 8 | 9 | 45 | 2 | 12 | 193 | 255 | 0 | 3 | 10 ];
+			output ivec2 out0 = [ ivec2(9, 8) | ivec2(12, 9) | ivec2(0, 45) | ivec2(255, 2) | ivec2(8, 12) | ivec2(45, 193) | ivec2(3, 255) | ivec2(2, 0) | ivec2(10, 3) | ivec2(193, 10) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_to_bvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 9 | 12 | 0 | 255 | 8 | 45 | 3 | 2 | 10 | 193 ];
+			input uint in1 = [ 8 | 9 | 45 | 2 | 12 | 193 | 255 | 0 | 3 | 10 ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_to_vec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			output vec2 out0 = [ vec2(1.0, 1.0) | vec2(0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_to_ivec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			output ivec2 out0 = [ ivec2(1, 1) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_to_bvec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_int_to_vec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 3.5 | 0.0 | 2.0 | -8.25 | 36.8125 | -20.125 | 1.0 | 1.0 | -0.5 ];
+			input int in1 = [ -66 | 1 | 255 | -192 | 8 | 2 | 0 | 5 | -12 | 11 ];
+			output vec2 out0 = [ vec2(0.0, -66.0) | vec2(3.5, 1.0) | vec2(0.0, 255.0) | vec2(2.0, -192.0) | vec2(-8.25, 8.0) | vec2(36.8125, 2.0) | vec2(-20.125, 0.0) | vec2(1.0, 5.0) | vec2(1.0, -12.0) | vec2(-0.5, 11.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_int_to_ivec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 3.5 | 0.0 | 2.0 | -8.25 | 36.8125 | -20.125 | 1.0 | 1.0 | -0.5 ];
+			input int in1 = [ -66 | 1 | 255 | -192 | 8 | 2 | 0 | 5 | -12 | 11 ];
+			output ivec2 out0 = [ ivec2(0, -66) | ivec2(3, 1) | ivec2(0, 255) | ivec2(2, -192) | ivec2(-8, 8) | ivec2(36, 2) | ivec2(-20, 0) | ivec2(1, 5) | ivec2(1, -12) | ivec2(0, 11) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_int_to_bvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 3.5 | 0.0 | 2.0 | -8.25 | 36.8125 | -20.125 | 1.0 | 1.0 | -0.5 ];
+			input int in1 = [ -66 | 1 | 255 | -192 | 8 | 2 | 0 | 5 | -12 | 11 ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bool_to_vec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 3.5 | 1.0 | -20.125 | -8.25 | 0.0 | -0.5 | 36.8125 ];
+			input bool in1 = [ false | true | true | false | false | true | false | true ];
+			output vec2 out0 = [ vec2(2.0, 0.0) | vec2(3.5, 1.0) | vec2(1.0, 1.0) | vec2(-20.125, 0.0) | vec2(-8.25, 0.0) | vec2(0.0, 1.0) | vec2(-0.5, 0.0) | vec2(36.8125, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bool_to_ivec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 3.5 | 1.0 | -20.125 | -8.25 | 0.0 | -0.5 | 36.8125 ];
+			input bool in1 = [ false | true | true | false | false | true | false | true ];
+			output ivec2 out0 = [ ivec2(2, 0) | ivec2(3, 1) | ivec2(1, 1) | ivec2(-20, 0) | ivec2(-8, 0) | ivec2(0, 1) | ivec2(0, 0) | ivec2(36, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bool_to_bvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 3.5 | 1.0 | -20.125 | -8.25 | 0.0 | -0.5 | 36.8125 ];
+			input bool in1 = [ false | true | true | false | false | true | false | true ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, false) | bvec2(true, false) | bvec2(false, true) | bvec2(true, false) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_bool_to_vec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 255 | 2 | -12 | 1 | -192 | 5 | 8 | 0 | -66 | 11 ];
+			input bool in1 = [ true | false | false | false | true | false | true | false | true | true ];
+			output vec2 out0 = [ vec2(255.0, 1.0) | vec2(2.0, 0.0) | vec2(-12.0, 0.0) | vec2(1.0, 0.0) | vec2(-192.0, 1.0) | vec2(5.0, 0.0) | vec2(8.0, 1.0) | vec2(0.0, 0.0) | vec2(-66.0, 1.0) | vec2(11.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_bool_to_ivec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 255 | 2 | -12 | 1 | -192 | 5 | 8 | 0 | -66 | 11 ];
+			input bool in1 = [ true | false | false | false | true | false | true | false | true | true ];
+			output ivec2 out0 = [ ivec2(255, 1) | ivec2(2, 0) | ivec2(-12, 0) | ivec2(1, 0) | ivec2(-192, 1) | ivec2(5, 0) | ivec2(8, 1) | ivec2(0, 0) | ivec2(-66, 1) | ivec2(11, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_bool_to_bvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 255 | 2 | -12 | 1 | -192 | 5 | 8 | 0 | -66 | 11 ];
+			input bool in1 = [ true | false | false | false | true | false | true | false | true | true ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(true, false) | bvec2(true, false) | bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(false, false) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uint_to_vec2
+		version 310 es
+		values
+		{
+			input int in0 = [ -66 | 1 | -192 | -12 | 5 | 255 | 11 | 0 | 2 | 8 ];
+			input uint in1 = [ 193 | 0 | 2 | 10 | 255 | 12 | 45 | 8 | 9 | 3 ];
+			output vec2 out0 = [ vec2(-66.0, 193.0) | vec2(1.0, 0.0) | vec2(-192.0, 2.0) | vec2(-12.0, 10.0) | vec2(5.0, 255.0) | vec2(255.0, 12.0) | vec2(11.0, 45.0) | vec2(0.0, 8.0) | vec2(2.0, 9.0) | vec2(8.0, 3.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uint_to_ivec2
+		version 310 es
+		values
+		{
+			input int in0 = [ -66 | 1 | -192 | -12 | 5 | 255 | 11 | 0 | 2 | 8 ];
+			input uint in1 = [ 193 | 0 | 2 | 10 | 255 | 12 | 45 | 8 | 9 | 3 ];
+			output ivec2 out0 = [ ivec2(-66, 193) | ivec2(1, 0) | ivec2(-192, 2) | ivec2(-12, 10) | ivec2(5, 255) | ivec2(255, 12) | ivec2(11, 45) | ivec2(0, 8) | ivec2(2, 9) | ivec2(8, 3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uint_to_bvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ -66 | 1 | -192 | -12 | 5 | 255 | 11 | 0 | 2 | 8 ];
+			input uint in1 = [ 193 | 0 | 2 | 10 | 255 | 12 | 45 | 8 | 9 | 3 ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_float_to_vec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 12 | 0 | 8 | 193 | 3 | 10 | 9 | 2 | 45 | 255 ];
+			input float in1 = [ -20.125 | 0.0 | 3.5 | -8.25 | 0.0 | 1.0 | 2.0 | 36.8125 | -0.5 | 1.0 ];
+			output vec2 out0 = [ vec2(12.0, -20.125) | vec2(0.0, 0.0) | vec2(8.0, 3.5) | vec2(193.0, -8.25) | vec2(3.0, 0.0) | vec2(10.0, 1.0) | vec2(9.0, 2.0) | vec2(2.0, 36.8125) | vec2(45.0, -0.5) | vec2(255.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = vec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_float_to_ivec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 12 | 0 | 8 | 193 | 3 | 10 | 9 | 2 | 45 | 255 ];
+			input float in1 = [ -20.125 | 0.0 | 3.5 | -8.25 | 0.0 | 1.0 | 2.0 | 36.8125 | -0.5 | 1.0 ];
+			output ivec2 out0 = [ ivec2(12, -20) | ivec2(0, 0) | ivec2(8, 3) | ivec2(193, -8) | ivec2(3, 0) | ivec2(10, 1) | ivec2(9, 2) | ivec2(2, 36) | ivec2(45, 0) | ivec2(255, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = ivec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_float_to_bvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 12 | 0 | 8 | 193 | 3 | 10 | 9 | 2 | 45 | 255 ];
+			input float in1 = [ -20.125 | 0.0 | 3.5 | -8.25 | 0.0 | 1.0 | 2.0 | 36.8125 | -0.5 | 1.0 ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, false) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) | bvec2(true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = bvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_to_uvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 8.25 | 36.8125 | 1.0 | 0.5 | 20.125 | 0.0 | 2.0 | 3.5 ];
+			input float in1 = [ 0.5 | 36.8125 | 0.0 | 2.0 | 8.25 | 20.125 | 1.0 | 3.5 ];
+			output uvec2 out0 = [ uvec2(8, 0) | uvec2(36, 36) | uvec2(1, 0) | uvec2(0, 2) | uvec2(20, 8) | uvec2(0, 20) | uvec2(2, 1) | uvec2(3, 3) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_to_uvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 0 | 12 | 8 | 11 | 255 | 66 | 192 | 2 | 5 | 1 ];
+			input int in1 = [ 11 | 12 | 2 | 5 | 66 | 192 | 255 | 0 | 1 | 8 ];
+			output uvec2 out0 = [ uvec2(0, 11) | uvec2(12, 12) | uvec2(8, 2) | uvec2(11, 5) | uvec2(255, 66) | uvec2(66, 192) | uvec2(192, 255) | uvec2(2, 0) | uvec2(5, 1) | uvec2(1, 8) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_to_uvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 3 | 9 | 10 | 193 | 8 | 0 | 255 | 45 | 2 | 12 ];
+			input uint in1 = [ 0 | 2 | 12 | 3 | 10 | 9 | 45 | 193 | 255 | 8 ];
+			output uvec2 out0 = [ uvec2(3, 0) | uvec2(9, 2) | uvec2(10, 12) | uvec2(193, 3) | uvec2(8, 10) | uvec2(0, 9) | uvec2(255, 45) | uvec2(45, 193) | uvec2(2, 255) | uvec2(12, 8) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_to_uvec2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			output uvec2 out0 = [ uvec2(1, 1) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_int_to_uvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 8.25 | 1.0 | 0.5 | 3.5 | 2.0 | 0.0 | 36.8125 | 1.0 | 0.0 | 20.125 ];
+			input int in1 = [ 0 | 255 | 12 | 5 | 192 | 2 | 66 | 11 | 1 | 8 ];
+			output uvec2 out0 = [ uvec2(8, 0) | uvec2(1, 255) | uvec2(0, 12) | uvec2(3, 5) | uvec2(2, 192) | uvec2(0, 2) | uvec2(36, 66) | uvec2(1, 11) | uvec2(0, 1) | uvec2(20, 8) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bool_to_uvec2
+		version 310 es
+		values
+		{
+			input float in0 = [ 3.5 | 1.0 | 8.25 | 0.5 | 2.0 | 36.8125 | 0.0 | 20.125 ];
+			input bool in1 = [ true | false | true | false | true | false | false | true ];
+			output uvec2 out0 = [ uvec2(3, 1) | uvec2(1, 0) | uvec2(8, 1) | uvec2(0, 0) | uvec2(2, 1) | uvec2(36, 0) | uvec2(0, 0) | uvec2(20, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_bool_to_uvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 12 | 11 | 0 | 5 | 8 | 255 | 2 | 1 | 66 | 192 ];
+			input bool in1 = [ true | true | false | false | false | true | false | false | true | true ];
+			output uvec2 out0 = [ uvec2(12, 1) | uvec2(11, 1) | uvec2(0, 0) | uvec2(5, 0) | uvec2(8, 0) | uvec2(255, 1) | uvec2(2, 0) | uvec2(1, 0) | uvec2(66, 1) | uvec2(192, 1) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uint_to_uvec2
+		version 310 es
+		values
+		{
+			input int in0 = [ 8 | 5 | 1 | 0 | 11 | 12 | 192 | 66 | 255 | 2 ];
+			input uint in1 = [ 8 | 10 | 45 | 255 | 9 | 193 | 2 | 3 | 0 | 12 ];
+			output uvec2 out0 = [ uvec2(8, 8) | uvec2(5, 10) | uvec2(1, 45) | uvec2(0, 255) | uvec2(11, 9) | uvec2(12, 193) | uvec2(192, 2) | uvec2(66, 3) | uvec2(255, 0) | uvec2(2, 12) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_float_to_uvec2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 9 | 45 | 8 | 3 | 10 | 2 | 193 | 12 | 255 | 0 ];
+			input float in1 = [ 3.5 | 20.125 | 2.0 | 0.0 | 1.0 | 36.8125 | 8.25 | 1.0 | 0.0 | 0.5 ];
+			output uvec2 out0 = [ uvec2(9, 3) | uvec2(45, 20) | uvec2(8, 2) | uvec2(3, 0) | uvec2(10, 1) | uvec2(2, 36) | uvec2(193, 8) | uvec2(12, 1) | uvec2(255, 0) | uvec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = uvec2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # vector_combine
+group matrix_combine "Matrix Combine Constructors"
+
+	case vec2_vec2_to_mat2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) | vec2(0.0, 0.5) ];
+			input vec2 in1 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) ];
+			output mat2 out0 = [ mat2(1.0, 1.25, 0.0, 0.5) | mat2(-32.0, 64.0, 1.0, 1.25) | mat2(-0.5, -2.25, -0.75, -0.0322580645161) | mat2(-0.75, -0.0322580645161, -32.0, 64.0) | mat2(0.0, 0.5, -0.5, -2.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec2_bvec2_to_mat2
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(false, true) | bvec2(true, true) | bvec2(true, false) | bvec2(false, false) | bvec2(false, false) ];
+			input bvec2 in1 = [ bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, true) ];
+			output mat2 out0 = [ mat2(0.0, 1.0, 0.0, 0.0) | mat2(1.0, 1.0, 1.0, 0.0) | mat2(1.0, 0.0, 0.0, 0.0) | mat2(0.0, 0.0, 1.0, 1.0) | mat2(0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_to_mat2
+		version 310 es
+		values
+		{
+			input float in0 = [ -8.25 | 3.5 | 36.8125 | 2.0 | -20.125 | 1.0 | -0.5 | 0.0 ];
+			input float in1 = [ 3.5 | -20.125 | 1.0 | 0.0 | -8.25 | 2.0 | 36.8125 | -0.5 ];
+			input float in2 = [ 36.8125 | 3.5 | 0.0 | -20.125 | -0.5 | -8.25 | 1.0 | 2.0 ];
+			input float in3 = [ -0.5 | 0.0 | -8.25 | -20.125 | 2.0 | 3.5 | 1.0 | 36.8125 ];
+			output mat2 out0 = [ mat2(-8.25, 3.5, 36.8125, -0.5) | mat2(3.5, -20.125, 3.5, 0.0) | mat2(36.8125, 1.0, 0.0, -8.25) | mat2(2.0, 0.0, -20.125, -20.125) | mat2(-20.125, -8.25, -0.5, 2.0) | mat2(1.0, 2.0, -8.25, 3.5) | mat2(-0.5, 36.8125, 1.0, 1.0) | mat2(0.0, -0.5, 2.0, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_to_mat2
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | 1 | -192 | 11 | -66 | 255 | 0 | 8 | -12 | 5 ];
+			input int in1 = [ 11 | 255 | 5 | -66 | 8 | 2 | 0 | -12 | 1 | -192 ];
+			input int in2 = [ 11 | 1 | -12 | 255 | 5 | 0 | 8 | -192 | 2 | -66 ];
+			input int in3 = [ 2 | 1 | 0 | 8 | 255 | -66 | -192 | 11 | 5 | -12 ];
+			output mat2 out0 = [ mat2(2.0, 11.0, 11.0, 2.0) | mat2(1.0, 255.0, 1.0, 1.0) | mat2(-192.0, 5.0, -12.0, 0.0) | mat2(11.0, -66.0, 255.0, 8.0) | mat2(-66.0, 8.0, 5.0, 255.0) | mat2(255.0, 2.0, 0.0, -66.0) | mat2(0.0, 0.0, 8.0, -192.0) | mat2(8.0, -12.0, -192.0, 11.0) | mat2(-12.0, 1.0, 2.0, 5.0) | mat2(5.0, -192.0, -66.0, -12.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint_uint_uint_to_mat2
+		version 310 es
+		values
+		{
+			input uint in0 = [ 193 | 9 | 12 | 45 | 10 | 2 | 8 | 3 | 255 | 0 ];
+			input uint in1 = [ 0 | 255 | 12 | 193 | 3 | 2 | 45 | 9 | 8 | 10 ];
+			input uint in2 = [ 3 | 9 | 10 | 2 | 12 | 193 | 255 | 0 | 8 | 45 ];
+			input uint in3 = [ 45 | 12 | 9 | 3 | 2 | 255 | 10 | 8 | 193 | 0 ];
+			output mat2 out0 = [ mat2(193.0, 0.0, 3.0, 45.0) | mat2(9.0, 255.0, 9.0, 12.0) | mat2(12.0, 12.0, 10.0, 9.0) | mat2(45.0, 193.0, 2.0, 3.0) | mat2(10.0, 3.0, 12.0, 2.0) | mat2(2.0, 2.0, 193.0, 255.0) | mat2(8.0, 45.0, 255.0, 10.0) | mat2(3.0, 9.0, 0.0, 8.0) | mat2(255.0, 8.0, 8.0, 193.0) | mat2(0.0, 10.0, 45.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_to_mat2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ true | false ];
+			input bool in2 = [ true | false ];
+			input bool in3 = [ false | true ];
+			output mat2 out0 = [ mat2(1.0, 1.0, 1.0, 0.0) | mat2(0.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_to_mat2
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true | false | true | true | false | true | true | false | false ];
+			input float in1 = [ 2.0 | -0.5 | 0.0 | 1.0 | 1.0 | 36.8125 | 3.5 | 0.0 | -8.25 | -20.125 ];
+			input int in2 = [ 0 | -12 | 8 | -192 | 1 | -66 | 5 | 11 | 2 | 255 ];
+			input bool in3 = [ true | false | true | false | true | false | false | true | true | false ];
+			output mat2 out0 = [ mat2(0.0, 2.0, 0.0, 1.0) | mat2(1.0, -0.5, -12.0, 0.0) | mat2(0.0, 0.0, 8.0, 1.0) | mat2(1.0, 1.0, -192.0, 0.0) | mat2(1.0, 1.0, 1.0, 1.0) | mat2(0.0, 36.8125, -66.0, 0.0) | mat2(1.0, 3.5, 5.0, 0.0) | mat2(1.0, 0.0, 11.0, 1.0) | mat2(0.0, -8.25, 2.0, 1.0) | mat2(0.0, -20.125, 255.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_to_mat2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) | vec2(0.0, 0.5) ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) ];
+			output mat2 out0 = [ mat2(1.0, 1.25, 0.0, -2.0) | mat2(-32.0, 64.0, 0.0, 0.0) | mat2(-0.5, -2.25, 0.0, 0.0) | mat2(-0.75, -0.0322580645161, -32.0, 64.0) | mat2(0.0, 0.5, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec2_to_mat2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(0.0, 0.5) ];
+			input bvec2 in1 = [ bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) ];
+			output mat2 out0 = [ mat2(-0.5, -2.25, 0.0, 0.0) | mat2(-32.0, 64.0, 1.0, 0.0) | mat2(1.0, 1.25, 0.0, 0.0) | mat2(-0.75, -0.0322580645161, 0.0, 1.0) | mat2(0.0, 0.5, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_to_mat2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(false, false, false) ];
+			input float in1 = [ 36.8125 | -8.25 | 1.0 | -0.5 | 2.0 | -20.125 | 0.0 | 3.5 ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 0.0, 36.8125) | mat2(0.0, 1.0, 0.0, -8.25) | mat2(0.0, 0.0, 0.0, 1.0) | mat2(1.0, 1.0, 1.0, -0.5) | mat2(1.0, 0.0, 0.0, 2.0) | mat2(0.0, 1.0, 0.0, -20.125) | mat2(0.0, 0.0, 0.0, 0.0) | mat2(0.0, 0.0, 0.0, 3.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_to_mat2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-0.5, -2.25, -4.875) | vec3(1.0, 1.25, 1.125) | vec3(0.0, 0.5, 0.75) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input float in1 = [ -0.5 | -20.125 | 0.0 | 36.8125 | 3.5 | -8.25 | 2.0 | 1.0 ];
+			output mat2 out0 = [ mat2(1.0, 1.25, 1.125, -0.5) | mat2(-0.5, -2.25, -4.875, -20.125) | mat2(-0.5, -2.25, -4.875, 0.0) | mat2(1.0, 1.25, 1.125, 36.8125) | mat2(0.0, 0.5, 0.75, 3.5) | mat2(-32.0, 64.0, -51.0, -8.25) | mat2(0.0, 0.5, 0.75, 2.0) | mat2(-0.75, -0.0322580645161, 0.0526315789474, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2_int_to_mat2
+		version 310 es
+		values
+		{
+			input int in0 = [ 8 | -192 | 2 | 0 | -66 | 255 | 5 | 1 | -12 | 11 ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(1, 1) ];
+			input int in2 = [ 2 | 1 | -12 | 0 | 11 | 8 | 255 | -192 | 5 | -66 ];
+			output mat2 out0 = [ mat2(8.0, 0.0, -2.0, 2.0) | mat2(-192.0, 0.0, 0.0, 1.0) | mat2(2.0, -32.0, 64.0, -12.0) | mat2(0.0, 0.0, 0.0, 0.0) | mat2(-66.0, 0.0, 0.0, 11.0) | mat2(255.0, -32.0, 64.0, 8.0) | mat2(5.0, 0.0, 0.0, 255.0) | mat2(1.0, 0.0, -2.0, -192.0) | mat2(-12.0, 1.0, 1.0, 5.0) | mat2(11.0, 1.0, 1.0, -66.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_ivec2_to_mat2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | true | false | false | true | false | false ];
+			input float in1 = [ 1.0 | -0.5 | -20.125 | 36.8125 | 2.0 | 0.0 | -8.25 | 3.5 ];
+			input ivec2 in2 = [ ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, -2) ];
+			output mat2 out0 = [ mat2(1.0, 1.0, 0.0, 0.0) | mat2(1.0, -0.5, 0.0, 0.0) | mat2(1.0, -20.125, 1.0, 1.0) | mat2(0.0, 36.8125, 0.0, 0.0) | mat2(0.0, 2.0, 1.0, 1.0) | mat2(1.0, 0.0, 0.0, -2.0) | mat2(0.0, -8.25, -32.0, 64.0) | mat2(0.0, 3.5, 0.0, -2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_uvec3_to_mat2
+		version 310 es
+		values
+		{
+			input float in0 = [ 36.8125 | 2.0 | -0.5 | 0.0 | -20.125 | 1.0 | 3.5 | -8.25 ];
+			input uvec3 in1 = [ uvec3(1, 1, 1) | uvec3(0, 2, 4) | uvec3(0, 2, 4) | uvec3(0, 0, 0) | uvec3(32, 64, 51) | uvec3(0, 0, 0) | uvec3(0, 0, 0) | uvec3(1, 1, 1) ];
+			output mat2 out0 = [ mat2(36.8125, 1.0, 1.0, 1.0) | mat2(2.0, 0.0, 2.0, 4.0) | mat2(-0.5, 0.0, 2.0, 4.0) | mat2(0.0, 0.0, 0.0, 0.0) | mat2(-20.125, 32.0, 64.0, 51.0) | mat2(1.0, 0.0, 0.0, 0.0) | mat2(3.5, 0.0, 0.0, 0.0) | mat2(-8.25, 1.0, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_uvec2_bool_to_mat2
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | -66 | 5 | -192 | 11 | 0 | 8 | 2 | -12 | 255 ];
+			input uvec2 in1 = [ uvec2(0, 2) | uvec2(32, 64) | uvec2(1, 1) | uvec2(0, 0) | uvec2(0, 0) | uvec2(1, 1) | uvec2(0, 2) | uvec2(0, 0) | uvec2(0, 0) | uvec2(32, 64) ];
+			input bool in2 = [ true | false | true | false | false | false | true | true | true | false ];
+			output mat2 out0 = [ mat2(1.0, 0.0, 2.0, 1.0) | mat2(-66.0, 32.0, 64.0, 0.0) | mat2(5.0, 1.0, 1.0, 1.0) | mat2(-192.0, 0.0, 0.0, 0.0) | mat2(11.0, 0.0, 0.0, 0.0) | mat2(0.0, 1.0, 1.0, 0.0) | mat2(8.0, 0.0, 2.0, 1.0) | mat2(2.0, 0.0, 0.0, 1.0) | mat2(-12.0, 0.0, 0.0, 1.0) | mat2(255.0, 32.0, 64.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_vec3_to_mat2x3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) ];
+			input vec3 in1 = [ vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 1.25, 1.125, -32.0, 64.0, -51.0) | mat2x3(-0.75, -0.0322580645161, 0.0526315789474, -0.5, -2.25, -4.875) | mat2x3(-0.5, -2.25, -4.875, 0.0, 0.5, 0.75) | mat2x3(-32.0, 64.0, -51.0, 1.0, 1.25, 1.125) | mat2x3(0.0, 0.5, 0.75, -0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_bvec3_to_mat2x3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, false) | bvec3(true, false, false) ];
+			input bvec3 in1 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x3(0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat2x3(1.0, 1.0, 1.0, 1.0, 0.0, 0.0) | mat2x3(0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat2x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_float_float_to_mat2x3
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | -8.25 | -20.125 | 36.8125 | -0.5 | 2.0 | 3.5 | 0.0 ];
+			input float in1 = [ -0.5 | -20.125 | 36.8125 | -8.25 | 2.0 | 1.0 | 3.5 | 0.0 ];
+			input float in2 = [ 3.5 | 1.0 | 36.8125 | -20.125 | -8.25 | -0.5 | 2.0 | 0.0 ];
+			input float in3 = [ 1.0 | -8.25 | 0.0 | -20.125 | 2.0 | 3.5 | -0.5 | 36.8125 ];
+			input float in4 = [ 1.0 | 0.0 | 3.5 | 2.0 | -8.25 | -20.125 | -0.5 | 36.8125 ];
+			input float in5 = [ 2.0 | -20.125 | -8.25 | -0.5 | 3.5 | 1.0 | 36.8125 | 0.0 ];
+			output mat2x3 out0 = [ mat2x3(1.0, -0.5, 3.5, 1.0, 1.0, 2.0) | mat2x3(-8.25, -20.125, 1.0, -8.25, 0.0, -20.125) | mat2x3(-20.125, 36.8125, 36.8125, 0.0, 3.5, -8.25) | mat2x3(36.8125, -8.25, -20.125, -20.125, 2.0, -0.5) | mat2x3(-0.5, 2.0, -8.25, 2.0, -8.25, 3.5) | mat2x3(2.0, 1.0, -0.5, 3.5, -20.125, 1.0) | mat2x3(3.5, 3.5, 2.0, -0.5, -0.5, 36.8125) | mat2x3(0.0, 0.0, 0.0, 36.8125, 36.8125, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_int_int_to_mat2x3
+		version 310 es
+		values
+		{
+			input int in0 = [ 2 | 8 | -192 | 0 | 5 | -12 | 1 | 255 | -66 | 11 ];
+			input int in1 = [ 1 | -192 | 8 | 0 | -12 | 2 | 11 | 255 | -66 | 5 ];
+			input int in2 = [ -192 | 2 | -66 | 8 | 11 | 255 | 0 | 5 | -12 | 1 ];
+			input int in3 = [ 2 | 11 | 255 | 0 | -66 | -12 | 5 | -192 | 8 | 1 ];
+			input int in4 = [ 8 | 0 | -12 | -192 | 2 | -66 | 1 | 255 | 5 | 11 ];
+			input int in5 = [ 0 | 11 | 5 | 8 | -12 | 255 | -192 | 2 | 1 | -66 ];
+			output mat2x3 out0 = [ mat2x3(2.0, 1.0, -192.0, 2.0, 8.0, 0.0) | mat2x3(8.0, -192.0, 2.0, 11.0, 0.0, 11.0) | mat2x3(-192.0, 8.0, -66.0, 255.0, -12.0, 5.0) | mat2x3(0.0, 0.0, 8.0, 0.0, -192.0, 8.0) | mat2x3(5.0, -12.0, 11.0, -66.0, 2.0, -12.0) | mat2x3(-12.0, 2.0, 255.0, -12.0, -66.0, 255.0) | mat2x3(1.0, 11.0, 0.0, 5.0, 1.0, -192.0) | mat2x3(255.0, 255.0, 5.0, -192.0, 255.0, 2.0) | mat2x3(-66.0, -66.0, -12.0, 8.0, 5.0, 1.0) | mat2x3(11.0, 5.0, 1.0, 1.0, 11.0, -66.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_bool_bool_to_mat2x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ false | true ];
+			input bool in2 = [ false | true ];
+			input bool in3 = [ true | false ];
+			input bool in4 = [ true | false ];
+			input bool in5 = [ true | false ];
+			output mat2x3 out0 = [ mat2x3(1.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat2x3(0.0, 1.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_float_int_to_mat2x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true | false | true | false | true | false | true | true | false ];
+			input float in1 = [ 0.0 | -8.25 | 2.0 | -20.125 | 3.5 | 0.0 | -0.5 | 36.8125 | 1.0 | 1.0 ];
+			input int in2 = [ -66 | -12 | 2 | 8 | 255 | 11 | -192 | 1 | 5 | 0 ];
+			input bool in3 = [ true | false | true | false | false | true | true | false | true | false ];
+			input float in4 = [ 1.0 | 0.0 | -8.25 | 1.0 | 3.5 | -20.125 | -0.5 | 0.0 | 2.0 | 36.8125 ];
+			input int in5 = [ 255 | -192 | 1 | 2 | -12 | -66 | 8 | 0 | 11 | 5 ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, -66.0, 1.0, 1.0, 255.0) | mat2x3(1.0, -8.25, -12.0, 0.0, 0.0, -192.0) | mat2x3(0.0, 2.0, 2.0, 1.0, -8.25, 1.0) | mat2x3(1.0, -20.125, 8.0, 0.0, 1.0, 2.0) | mat2x3(0.0, 3.5, 255.0, 0.0, 3.5, -12.0) | mat2x3(1.0, 0.0, 11.0, 1.0, -20.125, -66.0) | mat2x3(0.0, -0.5, -192.0, 1.0, -0.5, 8.0) | mat2x3(1.0, 36.8125, 1.0, 0.0, 0.0, 0.0) | mat2x3(1.0, 1.0, 5.0, 1.0, 2.0, 11.0) | mat2x3(0.0, 1.0, 0.0, 0.0, 36.8125, 5.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_ivec3_to_mat2x3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input ivec3 in1 = [ ivec3(1, 1, 1) | ivec3(-32, 64, -51) | ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(0, 0, 0) ];
+			output mat2x3 out0 = [ mat2x3(1.0, 1.25, 1.125, 1.0, 1.0, 1.0) | mat2x3(-0.5, -2.25, -4.875, -32.0, 64.0, -51.0) | mat2x3(-32.0, 64.0, -51.0, 0.0, -2.0, -4.0) | mat2x3(0.0, 0.5, 0.75, 0.0, 0.0, 0.0) | mat2x3(-0.75, -0.0322580645161, 0.0526315789474, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec4_to_mat2x3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-32.0, 64.0) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) ];
+			input bvec4 in1 = [ bvec4(true, false, false, true) | bvec4(false, true, false, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output mat2x3 out0 = [ mat2x3(-32.0, 64.0, 1.0, 0.0, 0.0, 1.0) | mat2x3(0.0, 0.5, 0.0, 1.0, 0.0, 0.0) | mat2x3(-0.5, -2.25, 0.0, 0.0, 0.0, 1.0) | mat2x3(1.0, 1.25, 1.0, 1.0, 1.0, 1.0) | mat2x3(-0.75, -0.0322580645161, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_ivec2_to_mat2x3
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, false, false) | bvec3(false, true, false) ];
+			input float in1 = [ 1.0 | -8.25 | 36.8125 | 2.0 | 3.5 | -0.5 | -20.125 | 0.0 ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat2x3(0.0, 0.0, 0.0, -8.25, 0.0, 0.0) | mat2x3(1.0, 1.0, 1.0, 36.8125, -32.0, 64.0) | mat2x3(1.0, 0.0, 0.0, 2.0, 0.0, -2.0) | mat2x3(0.0, 0.0, 0.0, 3.5, 1.0, 1.0) | mat2x3(0.0, 1.0, 0.0, -0.5, 0.0, -2.0) | mat2x3(1.0, 0.0, 0.0, -20.125, 0.0, 0.0) | mat2x3(0.0, 1.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_bvec2_to_mat2x3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(1.0, 1.25, 1.125) ];
+			input float in1 = [ 0.0 | 36.8125 | 3.5 | -0.5 | -8.25 | 2.0 | 1.0 | -20.125 ];
+			input bvec2 in2 = [ bvec2(false, false) | bvec2(false, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(true, true) | bvec2(false, false) ];
+			output mat2x3 out0 = [ mat2x3(0.0, 0.5, 0.75, 0.0, 0.0, 0.0) | mat2x3(-0.5, -2.25, -4.875, 36.8125, 0.0, 1.0) | mat2x3(0.0, 0.5, 0.75, 3.5, 1.0, 0.0) | mat2x3(1.0, 1.25, 1.125, -0.5, 0.0, 1.0) | mat2x3(-0.5, -2.25, -4.875, -8.25, 0.0, 0.0) | mat2x3(-0.75, -0.0322580645161, 0.0526315789474, 2.0, 1.0, 0.0) | mat2x3(-32.0, 64.0, -51.0, 1.0, 1.0, 1.0) | mat2x3(1.0, 1.25, 1.125, -20.125, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_vec3_vec2_to_mat2x4
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(-0.5, -2.25, -4.875) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-32.0, 64.0, -51.0) ];
+			input vec3 in1 = [ vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(1.0, 1.25, 1.125) ];
+			input vec2 in2 = [ vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) ];
+			output mat2x4 out0 = [ mat2x4(-0.5, -2.25, -4.875, 0.0, 0.5, 0.75, -0.75, -0.0322580645161) | mat2x4(-0.75, -0.0322580645161, 0.0526315789474, -0.5, -2.25, -4.875, -32.0, 64.0) | mat2x4(0.0, 0.5, 0.75, -0.75, -0.0322580645161, 0.0526315789474, 1.0, 1.25) | mat2x4(1.0, 1.25, 1.125, -32.0, 64.0, -51.0, 0.0, 0.5) | mat2x4(-32.0, 64.0, -51.0, 1.0, 1.25, 1.125, -0.5, -2.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_ivec3_ivec2_to_mat2x4
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, 64, -51) ];
+			input ivec3 in1 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			input ivec2 in2 = [ ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) ];
+			output mat2x4 out0 = [ mat2x4(0.0, -2.0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x4(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, -2.0) | mat2x4(1.0, 1.0, 1.0, 0.0, -2.0, -4.0, 1.0, 1.0) | mat2x4(0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 0.0, 0.0) | mat2x4(-32.0, 64.0, -51.0, 0.0, 0.0, 0.0, -32.0, 64.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_float_float_int_bool_to_mat2x4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) ];
+			input ivec2 in1 = [ ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) ];
+			input float in2 = [ -8.25 | -0.5 | 3.5 | 36.8125 | 0.0 | 0.0 | 2.0 | -20.125 | 1.0 | 1.0 ];
+			input float in3 = [ 1.0 | 2.0 | -0.5 | 3.5 | 36.8125 | -8.25 | 1.0 | 0.0 | 0.0 | -20.125 ];
+			input int in4 = [ 255 | 8 | 11 | -12 | -192 | 0 | 2 | 1 | -66 | 5 ];
+			input bool in5 = [ true | false | false | true | false | true | true | false | true | false ];
+			output mat2x4 out0 = [ mat2x4(0.0, 0.5, 1.0, 1.0, -8.25, 1.0, 255.0, 1.0) | mat2x4(-32.0, 64.0, 0.0, -2.0, -0.5, 2.0, 8.0, 0.0) | mat2x4(-0.5, -2.25, -32.0, 64.0, 3.5, -0.5, 11.0, 0.0) | mat2x4(0.0, 0.5, 0.0, -2.0, 36.8125, 3.5, -12.0, 1.0) | mat2x4(-32.0, 64.0, 0.0, 0.0, 0.0, 36.8125, -192.0, 0.0) | mat2x4(1.0, 1.25, 0.0, 0.0, 0.0, -8.25, 0.0, 1.0) | mat2x4(-0.75, -0.0322580645161, -32.0, 64.0, 2.0, 1.0, 2.0, 1.0) | mat2x4(1.0, 1.25, 0.0, 0.0, -20.125, 0.0, 1.0, 0.0) | mat2x4(-0.5, -2.25, 0.0, 0.0, 1.0, 0.0, -66.0, 1.0) | mat2x4(-0.75, -0.0322580645161, 1.0, 1.0, 1.0, -20.125, 5.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_vec2_bool_bvec2_to_mat2x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true | false | true | true | true | false | false | false | true ];
+			input float in1 = [ 0.0 | -0.5 | -20.125 | -8.25 | 0.0 | 2.0 | 3.5 | 1.0 | 1.0 | 36.8125 ];
+			input int in2 = [ 2 | 1 | 255 | 8 | -66 | 0 | -12 | 5 | -192 | 11 ];
+			input vec2 in3 = [ vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) ];
+			input bool in4 = [ true | false | false | true | false | false | true | true | true | false ];
+			input bvec2 in5 = [ bvec2(true, false) | bvec2(true, true) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) | bvec2(false, true) | bvec2(false, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, false) ];
+			output mat2x4 out0 = [ mat2x4(0.0, 0.0, 2.0, -32.0, 64.0, 1.0, 1.0, 0.0) | mat2x4(1.0, -0.5, 1.0, -0.5, -2.25, 0.0, 1.0, 1.0) | mat2x4(0.0, -20.125, 255.0, 1.0, 1.25, 0.0, 0.0, 1.0) | mat2x4(1.0, -8.25, 8.0, -0.75, -0.0322580645161, 1.0, 1.0, 1.0) | mat2x4(1.0, 0.0, -66.0, 0.0, 0.5, 0.0, 0.0, 0.0) | mat2x4(1.0, 2.0, 0.0, 1.0, 1.25, 0.0, 0.0, 1.0) | mat2x4(0.0, 3.5, -12.0, -32.0, 64.0, 1.0, 0.0, 0.0) | mat2x4(0.0, 1.0, 5.0, -0.5, -2.25, 1.0, 0.0, 0.0) | mat2x4(0.0, 1.0, -192.0, 0.0, 0.5, 1.0, 0.0, 0.0) | mat2x4(1.0, 36.8125, 11.0, -0.75, -0.0322580645161, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec2_int_vec4_to_mat2x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | true | false | false | false | false | false | true | true ];
+			input bvec2 in1 = [ bvec2(true, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(false, true) | bvec2(false, false) ];
+			input int in2 = [ 8 | 1 | 5 | -66 | -192 | 11 | 255 | 0 | -12 | 2 ];
+			input vec4 in3 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) ];
+			output mat2x4 out0 = [ mat2x4(1.0, 1.0, 1.0, 8.0, 0.0, 0.5, 0.75, 0.825) | mat2x4(1.0, 0.0, 0.0, 1.0, 0.0, 0.5, 0.75, 0.825) | mat2x4(1.0, 1.0, 0.0, 5.0, -32.0, 64.0, -51.0, 24.0) | mat2x4(0.0, 0.0, 0.0, -66.0, 1.0, 1.25, 1.125, 1.75) | mat2x4(0.0, 1.0, 1.0, -192.0, -0.5, -2.25, -4.875, 9.0) | mat2x4(0.0, 1.0, 0.0, 11.0, 1.0, 1.25, 1.125, 1.75) | mat2x4(0.0, 0.0, 1.0, 255.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat2x4(0.0, 0.0, 0.0, 0.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat2x4(1.0, 0.0, 1.0, -12.0, -0.5, -2.25, -4.875, 9.0) | mat2x4(1.0, 0.0, 0.0, 2.0, -32.0, 64.0, -51.0, 24.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bvec4_ivec2_bool_to_mat2x4
+		version 310 es
+		values
+		{
+			input float in0 = [ 0.0 | 3.5 | 2.0 | -8.25 | -20.125 | 36.8125 | 1.0 | -0.5 ];
+			input bvec4 in1 = [ bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(false, true, false, false) | bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, false, false, false) ];
+			input ivec2 in2 = [ ivec2(0, -2) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(1, 1) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) ];
+			input bool in3 = [ true | true | false | true | false | false | false | true ];
+			output mat2x4 out0 = [ mat2x4(0.0, 1.0, 0.0, 0.0, 1.0, 0.0, -2.0, 1.0) | mat2x4(3.5, 1.0, 1.0, 1.0, 1.0, -32.0, 64.0, 1.0) | mat2x4(2.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0) | mat2x4(-8.25, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat2x4(-20.125, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat2x4(36.8125, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat2x4(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) | mat2x4(-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat2x4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_vec3_to_mat3x2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(-32.0, 64.0, -51.0) | vec3(1.0, 1.25, 1.125) ];
+			input vec3 in1 = [ vec3(1.0, 1.25, 1.125) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) ];
+			output mat3x2 out0 = [ mat3x2(-0.75, -0.0322580645161, 0.0526315789474, 1.0, 1.25, 1.125) | mat3x2(-0.5, -2.25, -4.875, -0.75, -0.0322580645161, 0.0526315789474) | mat3x2(0.0, 0.5, 0.75, -32.0, 64.0, -51.0) | mat3x2(-32.0, 64.0, -51.0, -0.5, -2.25, -4.875) | mat3x2(1.0, 1.25, 1.125, 0.0, 0.5, 0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_bvec3_to_mat3x2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			input bvec3 in1 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, true, false) | bvec3(true, false, false) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat3x2(1.0, 1.0, 1.0, 0.0, 1.0, 0.0) | mat3x2(0.0, 0.0, 0.0, 1.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_float_float_float_float_float_to_mat3x2
+		version 310 es
+		values
+		{
+			input float in0 = [ -8.25 | 36.8125 | -20.125 | -0.5 | 3.5 | 1.0 | 2.0 | 0.0 ];
+			input float in1 = [ 2.0 | 3.5 | -20.125 | 36.8125 | 1.0 | 0.0 | -8.25 | -0.5 ];
+			input float in2 = [ -0.5 | 2.0 | 1.0 | 0.0 | -8.25 | 36.8125 | -20.125 | 3.5 ];
+			input float in3 = [ 36.8125 | 0.0 | 1.0 | -0.5 | 2.0 | 3.5 | -20.125 | -8.25 ];
+			input float in4 = [ 36.8125 | 2.0 | 0.0 | -0.5 | 3.5 | -20.125 | -8.25 | 1.0 ];
+			input float in5 = [ 0.0 | 36.8125 | -20.125 | -0.5 | 3.5 | 2.0 | 1.0 | -8.25 ];
+			output mat3x2 out0 = [ mat3x2(-8.25, 2.0, -0.5, 36.8125, 36.8125, 0.0) | mat3x2(36.8125, 3.5, 2.0, 0.0, 2.0, 36.8125) | mat3x2(-20.125, -20.125, 1.0, 1.0, 0.0, -20.125) | mat3x2(-0.5, 36.8125, 0.0, -0.5, -0.5, -0.5) | mat3x2(3.5, 1.0, -8.25, 2.0, 3.5, 3.5) | mat3x2(1.0, 0.0, 36.8125, 3.5, -20.125, 2.0) | mat3x2(2.0, -8.25, -20.125, -20.125, -8.25, 1.0) | mat3x2(0.0, -0.5, 3.5, -8.25, 1.0, -8.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int_int_int_int_int_to_mat3x2
+		version 310 es
+		values
+		{
+			input int in0 = [ 8 | -192 | 2 | 11 | 255 | -66 | 5 | -12 | 1 | 0 ];
+			input int in1 = [ 1 | 2 | -12 | 5 | 0 | 255 | 8 | 11 | -192 | -66 ];
+			input int in2 = [ -12 | 11 | 2 | 1 | 8 | -66 | -192 | 5 | 255 | 0 ];
+			input int in3 = [ -192 | 0 | -12 | 11 | 1 | -66 | 8 | 255 | 2 | 5 ];
+			input int in4 = [ -12 | 5 | 0 | -66 | 255 | 8 | -192 | 11 | 2 | 1 ];
+			input int in5 = [ -66 | -12 | 8 | 2 | 255 | 0 | -192 | 11 | 1 | 5 ];
+			output mat3x2 out0 = [ mat3x2(8.0, 1.0, -12.0, -192.0, -12.0, -66.0) | mat3x2(-192.0, 2.0, 11.0, 0.0, 5.0, -12.0) | mat3x2(2.0, -12.0, 2.0, -12.0, 0.0, 8.0) | mat3x2(11.0, 5.0, 1.0, 11.0, -66.0, 2.0) | mat3x2(255.0, 0.0, 8.0, 1.0, 255.0, 255.0) | mat3x2(-66.0, 255.0, -66.0, -66.0, 8.0, 0.0) | mat3x2(5.0, 8.0, -192.0, 8.0, -192.0, -192.0) | mat3x2(-12.0, 11.0, 5.0, 255.0, 11.0, 11.0) | mat3x2(1.0, -192.0, 255.0, 2.0, 2.0, 1.0) | mat3x2(0.0, -66.0, 0.0, 5.0, 1.0, 5.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool_bool_bool_bool_bool_to_mat3x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false ];
+			input bool in1 = [ false | true ];
+			input bool in2 = [ false | true ];
+			input bool in3 = [ false | true ];
+			input bool in4 = [ false | true ];
+			input bool in5 = [ false | true ];
+			output mat3x2 out0 = [ mat3x2(1.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(0.0, 1.0, 1.0, 1.0, 1.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_bool_float_int_to_mat3x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | true | true | false | true | false | true | false | false ];
+			input float in1 = [ -20.125 | 0.0 | 3.5 | 0.0 | 1.0 | -8.25 | 1.0 | 2.0 | 36.8125 | -0.5 ];
+			input int in2 = [ 255 | -66 | 8 | -192 | 5 | 11 | 1 | 2 | 0 | -12 ];
+			input bool in3 = [ true | false | false | true | false | true | true | false | false | true ];
+			input float in4 = [ 0.0 | -20.125 | 1.0 | -8.25 | 0.0 | -0.5 | 2.0 | 3.5 | 1.0 | 36.8125 ];
+			input int in5 = [ -192 | 8 | 2 | 255 | -66 | -12 | 11 | 0 | 5 | 1 ];
+			output mat3x2 out0 = [ mat3x2(1.0, -20.125, 255.0, 1.0, 0.0, -192.0) | mat3x2(0.0, 0.0, -66.0, 0.0, -20.125, 8.0) | mat3x2(1.0, 3.5, 8.0, 0.0, 1.0, 2.0) | mat3x2(1.0, 0.0, -192.0, 1.0, -8.25, 255.0) | mat3x2(0.0, 1.0, 5.0, 0.0, 0.0, -66.0) | mat3x2(1.0, -8.25, 11.0, 1.0, -0.5, -12.0) | mat3x2(0.0, 1.0, 1.0, 1.0, 2.0, 11.0) | mat3x2(1.0, 2.0, 2.0, 0.0, 3.5, 0.0) | mat3x2(0.0, 36.8125, 0.0, 0.0, 1.0, 5.0) | mat3x2(0.0, -0.5, -12.0, 1.0, 36.8125, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_ivec3_to_mat3x2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) ];
+			input ivec3 in1 = [ ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.5, 0.75, 1.0, 1.0, 1.0) | mat3x2(1.0, 1.25, 1.125, 0.0, 0.0, 0.0) | mat3x2(-0.75, -0.0322580645161, 0.0526315789474, 0.0, -2.0, -4.0) | mat3x2(-32.0, 64.0, -51.0, -32.0, 64.0, -51.0) | mat3x2(-0.5, -2.25, -4.875, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_bvec4_to_mat3x2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) ];
+			input bvec4 in1 = [ bvec4(true, true, true, true) | bvec4(false, false, false, true) | bvec4(false, false, false, false) | bvec4(true, false, false, true) | bvec4(false, true, false, false) ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.5, 1.0, 1.0, 1.0, 1.0) | mat3x2(-0.75, -0.0322580645161, 0.0, 0.0, 0.0, 1.0) | mat3x2(-32.0, 64.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(-0.5, -2.25, 1.0, 0.0, 0.0, 1.0) | mat3x2(1.0, 1.25, 0.0, 1.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec3_float_ivec2_to_mat3x2
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, false, false) | bvec3(false, true, false) | bvec3(true, false, false) ];
+			input float in1 = [ -8.25 | 1.0 | 2.0 | -0.5 | -20.125 | 0.0 | 36.8125 | 3.5 ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(1, 1) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(-32, 64) ];
+			output mat3x2 out0 = [ mat3x2(0.0, 0.0, 0.0, -8.25, 1.0, 1.0) | mat3x2(1.0, 1.0, 1.0, 1.0, 1.0, 1.0) | mat3x2(0.0, 0.0, 0.0, 2.0, 0.0, 0.0) | mat3x2(0.0, 0.0, 0.0, -0.5, 0.0, -2.0) | mat3x2(0.0, 1.0, 0.0, -20.125, 0.0, 0.0) | mat3x2(1.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x2(0.0, 1.0, 0.0, 36.8125, 0.0, -2.0) | mat3x2(1.0, 0.0, 0.0, 3.5, -32.0, 64.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_float_bvec2_to_mat3x2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(0.0, 0.5, 0.75) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input float in1 = [ -8.25 | 36.8125 | -0.5 | 3.5 | 2.0 | -20.125 | 0.0 | 1.0 ];
+			input bvec2 in2 = [ bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) | bvec2(false, true) | bvec2(false, true) | bvec2(true, false) | bvec2(false, false) ];
+			output mat3x2 out0 = [ mat3x2(1.0, 1.25, 1.125, -8.25, 1.0, 0.0) | mat3x2(1.0, 1.25, 1.125, 36.8125, 0.0, 0.0) | mat3x2(-0.5, -2.25, -4.875, -0.5, 1.0, 1.0) | mat3x2(-0.5, -2.25, -4.875, 3.5, 0.0, 0.0) | mat3x2(-32.0, 64.0, -51.0, 2.0, 0.0, 1.0) | mat3x2(0.0, 0.5, 0.75, -20.125, 0.0, 1.0) | mat3x2(0.0, 0.5, 0.75, 0.0, 1.0, 0.0) | mat3x2(-0.75, -0.0322580645161, 0.0526315789474, 1.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_vec3_vec3_to_mat3
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input vec3 in1 = [ vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(1.0, 1.25, 1.125) | vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) ];
+			input vec3 in2 = [ vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) | vec3(1.0, 1.25, 1.125) | vec3(0.0, 0.5, 0.75) ];
+			output mat3 out0 = [ mat3(1.0, 1.25, 1.125, -0.75, -0.0322580645161, 0.0526315789474, -0.75, -0.0322580645161, 0.0526315789474) | mat3(-0.5, -2.25, -4.875, 1.0, 1.25, 1.125, -32.0, 64.0, -51.0) | mat3(-32.0, 64.0, -51.0, -32.0, 64.0, -51.0, -0.5, -2.25, -4.875) | mat3(0.0, 0.5, 0.75, -0.5, -2.25, -4.875, 1.0, 1.25, 1.125) | mat3(-0.75, -0.0322580645161, 0.0526315789474, 0.0, 0.5, 0.75, 0.0, 0.5, 0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_ivec3_ivec3_to_mat3
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			input ivec3 in1 = [ ivec3(0, 0, 0) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) | ivec3(1, 1, 1) ];
+			input ivec3 in2 = [ ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, 64, -51) | ivec3(0, -2, -4) | ivec3(0, 0, 0) ];
+			output mat3 out0 = [ mat3(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat3(0.0, -2.0, -4.0, 0.0, -2.0, -4.0, 0.0, 0.0, 0.0) | mat3(0.0, 0.0, 0.0, -32.0, 64.0, -51.0, -32.0, 64.0, -51.0) | mat3(-32.0, 64.0, -51.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0) | mat3(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_float_float_int_bool_bool_to_mat3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-32.0, 64.0) ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(-32, 64) ];
+			input float in2 = [ -0.5 | 3.5 | 0.0 | -20.125 | 1.0 | -8.25 | 0.0 | 1.0 | 2.0 | 36.8125 ];
+			input float in3 = [ 3.5 | 0.0 | -20.125 | 36.8125 | 2.0 | -8.25 | -0.5 | 1.0 | 0.0 | 1.0 ];
+			input int in4 = [ 0 | 11 | 5 | -192 | 8 | -66 | 1 | 2 | 255 | -12 ];
+			input bool in5 = [ true | true | true | false | true | false | false | false | true | false ];
+			input bool in6 = [ false | false | true | false | false | false | true | true | true | true ];
+			output mat3 out0 = [ mat3(1.0, 1.25, 0.0, 0.0, -0.5, 3.5, 0.0, 1.0, 0.0) | mat3(-0.5, -2.25, 0.0, -2.0, 3.5, 0.0, 11.0, 1.0, 0.0) | mat3(0.0, 0.5, 1.0, 1.0, 0.0, -20.125, 5.0, 1.0, 1.0) | mat3(-0.75, -0.0322580645161, 0.0, -2.0, -20.125, 36.8125, -192.0, 0.0, 0.0) | mat3(-32.0, 64.0, 0.0, 0.0, 1.0, 2.0, 8.0, 1.0, 0.0) | mat3(-0.75, -0.0322580645161, 0.0, 0.0, -8.25, -8.25, -66.0, 0.0, 0.0) | mat3(-0.5, -2.25, 1.0, 1.0, 0.0, -0.5, 1.0, 0.0, 1.0) | mat3(1.0, 1.25, -32.0, 64.0, 1.0, 1.0, 2.0, 0.0, 1.0) | mat3(0.0, 0.5, 0.0, 0.0, 2.0, 0.0, 255.0, 1.0, 1.0) | mat3(-32.0, 64.0, -32.0, 64.0, 36.8125, 1.0, -12.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2, in3, in4, in5, in6);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_vec2_bool_bvec2_float_to_mat3
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true | true | true | true | true | false | false | false | false ];
+			input float in1 = [ -8.25 | 1.0 | -0.5 | 36.8125 | 0.0 | 3.5 | -20.125 | 1.0 | 0.0 | 2.0 ];
+			input int in2 = [ 8 | -66 | 5 | 1 | 0 | 2 | -12 | -192 | 11 | 255 ];
+			input vec2 in3 = [ vec2(0.0, 0.5) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) ];
+			input bool in4 = [ true | false | true | false | false | true | true | false | true | false ];
+			input bvec2 in5 = [ bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) | bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) ];
+			input float in6 = [ -0.5 | 1.0 | 1.0 | 0.0 | 36.8125 | 2.0 | 0.0 | 3.5 | -20.125 | -8.25 ];
+			output mat3 out0 = [ mat3(0.0, -8.25, 8.0, 0.0, 0.5, 1.0, 0.0, 1.0, -0.5) | mat3(1.0, 1.0, -66.0, -32.0, 64.0, 0.0, 0.0, 0.0, 1.0) | mat3(1.0, -0.5, 5.0, 1.0, 1.25, 1.0, 1.0, 0.0, 1.0) | mat3(1.0, 36.8125, 1.0, -32.0, 64.0, 0.0, 0.0, 0.0, 0.0) | mat3(1.0, 0.0, 0.0, -0.5, -2.25, 0.0, 1.0, 1.0, 36.8125) | mat3(1.0, 3.5, 2.0, -0.75, -0.0322580645161, 1.0, 0.0, 0.0, 2.0) | mat3(0.0, -20.125, -12.0, -0.5, -2.25, 1.0, 1.0, 0.0, 0.0) | mat3(0.0, 1.0, -192.0, 0.0, 0.5, 0.0, 0.0, 0.0, 3.5) | mat3(0.0, 0.0, 11.0, 1.0, 1.25, 1.0, 0.0, 1.0, -20.125) | mat3(0.0, 2.0, 255.0, -0.75, -0.0322580645161, 0.0, 1.0, 1.0, -8.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2, in3, in4, in5, in6);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec2_int_vec4_bool_to_mat3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | false | true | true | false | false | true | false | false | true ];
+			input bvec2 in1 = [ bvec2(false, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) | bvec2(true, true) | bvec2(false, false) | bvec2(false, true) | bvec2(true, false) | bvec2(true, false) | bvec2(false, false) ];
+			input int in2 = [ -192 | 2 | 0 | 5 | 1 | -66 | 11 | -12 | 8 | 255 ];
+			input vec4 in3 = [ vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			input bool in4 = [ false | true | false | true | false | false | false | true | true | true ];
+			output mat3 out0 = [ mat3(1.0, 0.0, 0.0, -192.0, -32.0, 64.0, -51.0, 24.0, 0.0) | mat3(0.0, 0.0, 1.0, 2.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 1.0) | mat3(1.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.75, 0.825, 0.0) | mat3(1.0, 1.0, 1.0, 5.0, -32.0, 64.0, -51.0, 24.0, 1.0) | mat3(0.0, 1.0, 1.0, 1.0, 1.0, 1.25, 1.125, 1.75, 0.0) | mat3(0.0, 0.0, 0.0, -66.0, 0.0, 0.5, 0.75, 0.825, 0.0) | mat3(1.0, 0.0, 1.0, 11.0, 1.0, 1.25, 1.125, 1.75, 0.0) | mat3(0.0, 1.0, 0.0, -12.0, -0.5, -2.25, -4.875, 9.0, 1.0) | mat3(0.0, 1.0, 0.0, 8.0, -0.5, -2.25, -4.875, 9.0, 1.0) | mat3(1.0, 0.0, 0.0, 255.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2, in3, in4);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bvec4_ivec2_bool_bool_to_mat3
+		version 310 es
+		values
+		{
+			input float in0 = [ -8.25 | 2.0 | 36.8125 | 3.5 | 1.0 | -0.5 | -20.125 | 0.0 ];
+			input bvec4 in1 = [ bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, false, false, true) | bvec4(false, false, false, true) ];
+			input ivec2 in2 = [ ivec2(1, 1) | ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(1, 1) ];
+			input bool in3 = [ false | true | false | true | true | false | true | false ];
+			input bool in4 = [ true | false | false | false | true | true | false | true ];
+			output mat3 out0 = [ mat3(-8.25, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0) | mat3(2.0, 0.0, 1.0, 0.0, 0.0, 0.0, -2.0, 1.0, 0.0) | mat3(36.8125, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat3(3.5, 1.0, 1.0, 1.0, 1.0, -32.0, 64.0, 1.0, 0.0) | mat3(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0) | mat3(-0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat3(-20.125, 1.0, 0.0, 0.0, 1.0, 0.0, -2.0, 1.0, 0.0) | mat3(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3(in0, in1, in2, in3, in4);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_vec4_vec4_to_mat3x4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input vec4 in1 = [ vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) ];
+			input vec4 in2 = [ vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			output mat3x4 out0 = [ mat3x4(-0.75, -0.0322580645161, 0.0526315789474, 0.25, -0.75, -0.0322580645161, 0.0526315789474, 0.25, -32.0, 64.0, -51.0, 24.0) | mat3x4(1.0, 1.25, 1.125, 1.75, -0.5, -2.25, -4.875, 9.0, 1.0, 1.25, 1.125, 1.75) | mat3x4(-32.0, 64.0, -51.0, 24.0, 0.0, 0.5, 0.75, 0.825, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat3x4(-0.5, -2.25, -4.875, 9.0, -32.0, 64.0, -51.0, 24.0, -0.5, -2.25, -4.875, 9.0) | mat3x4(0.0, 0.5, 0.75, 0.825, 1.0, 1.25, 1.125, 1.75, 0.0, 0.5, 0.75, 0.825) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_ivec4_ivec4_to_mat3x4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) ];
+			input ivec4 in1 = [ ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) ];
+			input ivec4 in2 = [ ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) ];
+			output mat3x4 out0 = [ mat3x4(0.0, -2.0, -4.0, 9.0, 0.0, -2.0, -4.0, 9.0, 0.0, -2.0, -4.0, 9.0) | mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(-32.0, 64.0, -51.0, 24.0, -32.0, 64.0, -51.0, 24.0, 1.0, 1.0, 1.0, 1.0) | mat3x4(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_float_float_float_int_int_bool_bool_bool_to_mat3x4
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(0.0, 0.5) | vec2(-32.0, 64.0) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(-0.5, -2.25) ];
+			input ivec2 in1 = [ ivec2(0, 0) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, -2) ];
+			input float in2 = [ 1.0 | -8.25 | 2.0 | 3.5 | -20.125 | 36.8125 | 0.0 | 1.0 | -0.5 | 0.0 ];
+			input float in3 = [ -0.5 | 36.8125 | 1.0 | 1.0 | 0.0 | 3.5 | 2.0 | 0.0 | -8.25 | -20.125 ];
+			input float in4 = [ -8.25 | 1.0 | 1.0 | 0.0 | 2.0 | 36.8125 | 0.0 | -20.125 | 3.5 | -0.5 ];
+			input int in5 = [ 11 | 2 | 8 | 5 | 0 | -192 | 1 | -12 | 255 | -66 ];
+			input int in6 = [ -12 | 5 | 8 | 1 | 0 | 255 | 11 | -192 | -66 | 2 ];
+			input bool in7 = [ true | true | true | false | false | false | true | false | true | false ];
+			input bool in8 = [ true | true | true | false | true | false | true | false | false | false ];
+			input bool in9 = [ true | false | true | false | true | true | false | false | false | true ];
+			output mat3x4 out0 = [ mat3x4(1.0, 1.25, 0.0, 0.0, 1.0, -0.5, -8.25, 11.0, -12.0, 1.0, 1.0, 1.0) | mat3x4(0.0, 0.5, 0.0, 0.0, -8.25, 36.8125, 1.0, 2.0, 5.0, 1.0, 1.0, 0.0) | mat3x4(0.0, 0.5, -32.0, 64.0, 2.0, 1.0, 1.0, 8.0, 8.0, 1.0, 1.0, 1.0) | mat3x4(-32.0, 64.0, 1.0, 1.0, 3.5, 1.0, 0.0, 5.0, 1.0, 0.0, 0.0, 0.0) | mat3x4(-32.0, 64.0, 1.0, 1.0, -20.125, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 1.0) | mat3x4(-0.75, -0.0322580645161, -32.0, 64.0, 36.8125, 3.5, 36.8125, -192.0, 255.0, 0.0, 0.0, 1.0) | mat3x4(1.0, 1.25, 0.0, 0.0, 0.0, 2.0, 0.0, 1.0, 11.0, 1.0, 1.0, 0.0) | mat3x4(-0.75, -0.0322580645161, 0.0, -2.0, 1.0, 0.0, -20.125, -12.0, -192.0, 0.0, 0.0, 0.0) | mat3x4(-0.5, -2.25, 0.0, 0.0, -0.5, -8.25, 3.5, 255.0, -66.0, 1.0, 0.0, 0.0) | mat3x4(-0.5, -2.25, 0.0, -2.0, 0.0, -20.125, -0.5, -66.0, 2.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2, in3, in4, in5, in6, in7, in8, in9);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_vec3_bool_bvec3_float_bool_to_mat3x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | false | true | true | true | true | false | false | false | true ];
+			input float in1 = [ 36.8125 | -8.25 | 1.0 | 0.0 | 0.0 | 1.0 | 2.0 | 3.5 | -0.5 | -20.125 ];
+			input int in2 = [ -66 | -192 | 255 | 8 | 0 | -12 | 5 | 2 | 11 | 1 ];
+			input vec3 in3 = [ vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(0.0, 0.5, 0.75) | vec3(-32.0, 64.0, -51.0) | vec3(1.0, 1.25, 1.125) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-0.5, -2.25, -4.875) ];
+			input bool in4 = [ false | true | true | true | false | false | true | true | false | false ];
+			input bvec3 in5 = [ bvec3(true, false, false) | bvec3(true, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, false) ];
+			input float in6 = [ -8.25 | 1.0 | -0.5 | 36.8125 | 0.0 | 2.0 | -20.125 | 1.0 | 0.0 | 3.5 ];
+			input bool in7 = [ true | false | false | true | true | false | true | false | false | true ];
+			output mat3x4 out0 = [ mat3x4(0.0, 36.8125, -66.0, -0.75, -0.0322580645161, 0.0526315789474, 0.0, 1.0, 0.0, 0.0, -8.25, 1.0) | mat3x4(0.0, -8.25, -192.0, -32.0, 64.0, -51.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(1.0, 1.0, 255.0, 0.0, 0.5, 0.75, 1.0, 0.0, 1.0, 0.0, -0.5, 0.0) | mat3x4(1.0, 0.0, 8.0, -0.75, -0.0322580645161, 0.0526315789474, 1.0, 0.0, 0.0, 0.0, 36.8125, 1.0) | mat3x4(1.0, 0.0, 0.0, 0.0, 0.5, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0) | mat3x4(1.0, 1.0, -12.0, -32.0, 64.0, -51.0, 0.0, 1.0, 1.0, 1.0, 2.0, 0.0) | mat3x4(0.0, 2.0, 5.0, 1.0, 1.25, 1.125, 1.0, 1.0, 1.0, 1.0, -20.125, 1.0) | mat3x4(0.0, 3.5, 2.0, 1.0, 1.25, 1.125, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0) | mat3x4(0.0, -0.5, 11.0, -0.5, -2.25, -4.875, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat3x4(1.0, -20.125, 1.0, -0.5, -2.25, -4.875, 0.0, 0.0, 0.0, 0.0, 3.5, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2, in3, in4, in5, in6, in7);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec4_int_vec4_bool_float_to_mat3x4
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | true | true | true | false | false | false | true | false | true ];
+			input bvec4 in1 = [ bvec4(false, false, false, false) | bvec4(true, false, false, true) | bvec4(false, true, false, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, false, false, true) ];
+			input int in2 = [ 255 | 2 | -192 | -12 | 11 | 1 | 0 | -66 | 8 | 5 ];
+			input vec4 in3 = [ vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) ];
+			input bool in4 = [ true | true | true | false | false | false | true | true | false | false ];
+			input float in5 = [ 36.8125 | 2.0 | -8.25 | 0.0 | 1.0 | 1.0 | -0.5 | 3.5 | 0.0 | -20.125 ];
+			output mat3x4 out0 = [ mat3x4(0.0, 0.0, 0.0, 0.0, 0.0, 255.0, -0.5, -2.25, -4.875, 9.0, 1.0, 36.8125) | mat3x4(1.0, 1.0, 0.0, 0.0, 1.0, 2.0, 1.0, 1.25, 1.125, 1.75, 1.0, 2.0) | mat3x4(1.0, 0.0, 1.0, 0.0, 0.0, -192.0, 1.0, 1.25, 1.125, 1.75, 1.0, -8.25) | mat3x4(1.0, 0.0, 0.0, 0.0, 1.0, -12.0, 0.0, 0.5, 0.75, 0.825, 0.0, 0.0) | mat3x4(0.0, 1.0, 1.0, 1.0, 1.0, 11.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 0.0, 1.0) | mat3x4(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, -32.0, 64.0, -51.0, 24.0, 0.0, 1.0) | mat3x4(0.0, 1.0, 1.0, 1.0, 1.0, 0.0, -32.0, 64.0, -51.0, 24.0, 1.0, -0.5) | mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, -66.0, 0.0, 0.5, 0.75, 0.825, 1.0, 3.5) | mat3x4(0.0, 0.0, 1.0, 0.0, 0.0, 8.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 0.0, 0.0) | mat3x4(1.0, 1.0, 0.0, 0.0, 1.0, 5.0, -0.5, -2.25, -4.875, 9.0, 0.0, -20.125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bvec4_ivec4_bool_bool_int_to_mat3x4
+		version 310 es
+		values
+		{
+			input float in0 = [ 36.8125 | 1.0 | 0.0 | 3.5 | -8.25 | -20.125 | 2.0 | 0.0 | 1.0 | -0.5 ];
+			input bvec4 in1 = [ bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(true, false, false, true) | bvec4(true, false, false, true) | bvec4(false, true, false, false) | bvec4(false, false, false, true) | bvec4(false, false, false, false) ];
+			input ivec4 in2 = [ ivec4(0, 0, 0, 0) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) ];
+			input bool in3 = [ true | false | true | true | false | true | true | false | false | false ];
+			input bool in4 = [ true | false | false | true | true | false | false | false | true | true ];
+			input int in5 = [ 1 | 5 | -12 | 8 | -192 | 2 | -66 | 255 | 11 | 0 ];
+			output mat3x4 out0 = [ mat3x4(36.8125, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat3x4(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0, 9.0, 0.0, 0.0, 5.0) | mat3x4(0.0, 0.0, 1.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0, 1.0, 0.0, -12.0) | mat3x4(3.5, 0.0, 0.0, 0.0, 1.0, 0.0, -2.0, -4.0, 9.0, 1.0, 1.0, 8.0) | mat3x4(-8.25, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, -192.0) | mat3x4(-20.125, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 2.0) | mat3x4(2.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -66.0) | mat3x4(0.0, 0.0, 1.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0, 0.0, 0.0, 255.0) | mat3x4(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 11.0) | mat3x4(-0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat3x4(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec3_vec3_vec2_to_mat4x2
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(1.0, 1.25, 1.125) | vec3(-32.0, 64.0, -51.0) | vec3(0.0, 0.5, 0.75) | vec3(-0.5, -2.25, -4.875) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input vec3 in1 = [ vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(-0.5, -2.25, -4.875) | vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) ];
+			input vec2 in2 = [ vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(0.0, 0.5) ];
+			output mat4x2 out0 = [ mat4x2(1.0, 1.25, 1.125, -32.0, 64.0, -51.0, 1.0, 1.25) | mat4x2(-32.0, 64.0, -51.0, -0.75, -0.0322580645161, 0.0526315789474, -0.5, -2.25) | mat4x2(0.0, 0.5, 0.75, -0.5, -2.25, -4.875, -0.75, -0.0322580645161) | mat4x2(-0.5, -2.25, -4.875, 0.0, 0.5, 0.75, -32.0, 64.0) | mat4x2(-0.75, -0.0322580645161, 0.0526315789474, 1.0, 1.25, 1.125, 0.0, 0.5) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec3_ivec3_ivec2_to_mat4x2
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(-32, 64, -51) ];
+			input ivec3 in1 = [ ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, 64, -51) ];
+			input ivec2 in2 = [ ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) ];
+			output mat4x2 out0 = [ mat4x2(0.0, 0.0, 0.0, 0.0, -2.0, -4.0, -32.0, 64.0) | mat4x2(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0) | mat4x2(0.0, -2.0, -4.0, 1.0, 1.0, 1.0, 0.0, 0.0) | mat4x2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0) | mat4x2(-32.0, 64.0, -51.0, -32.0, 64.0, -51.0, 0.0, -2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_float_float_int_bool_to_mat4x2
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(0.0, 0.5) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) ];
+			input float in2 = [ 3.5 | -8.25 | 2.0 | 36.8125 | -0.5 | 1.0 | 1.0 | 0.0 | -20.125 | 0.0 ];
+			input float in3 = [ 0.0 | 36.8125 | 3.5 | 1.0 | -0.5 | -8.25 | 2.0 | 0.0 | -20.125 | 1.0 ];
+			input int in4 = [ -12 | -66 | 11 | 5 | 8 | 255 | -192 | 2 | 1 | 0 ];
+			input bool in5 = [ true | true | false | true | false | true | false | true | false | false ];
+			output mat4x2 out0 = [ mat4x2(-0.5, -2.25, 0.0, -2.0, 3.5, 0.0, -12.0, 1.0) | mat4x2(0.0, 0.5, 0.0, 0.0, -8.25, 36.8125, -66.0, 1.0) | mat4x2(1.0, 1.25, -32.0, 64.0, 2.0, 3.5, 11.0, 0.0) | mat4x2(0.0, 0.5, 1.0, 1.0, 36.8125, 1.0, 5.0, 1.0) | mat4x2(-32.0, 64.0, 1.0, 1.0, -0.5, -0.5, 8.0, 0.0) | mat4x2(-0.75, -0.0322580645161, 0.0, 0.0, 1.0, -8.25, 255.0, 1.0) | mat4x2(-0.75, -0.0322580645161, -32.0, 64.0, 1.0, 2.0, -192.0, 0.0) | mat4x2(-32.0, 64.0, 0.0, 0.0, 0.0, 0.0, 2.0, 1.0) | mat4x2(-0.5, -2.25, 0.0, 0.0, -20.125, -20.125, 1.0, 0.0) | mat4x2(1.0, 1.25, 0.0, -2.0, 0.0, 1.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_vec2_bool_bvec2_to_mat4x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | false | true | true | true | false | false | true | false | true ];
+			input float in1 = [ 36.8125 | -8.25 | 3.5 | 1.0 | 2.0 | -0.5 | 0.0 | 1.0 | -20.125 | 0.0 ];
+			input int in2 = [ -66 | 1 | -192 | 2 | 11 | 0 | 255 | 8 | 5 | -12 ];
+			input vec2 in3 = [ vec2(-0.75, -0.0322580645161) | vec2(-0.75, -0.0322580645161) | vec2(-32.0, 64.0) | vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(0.0, 0.5) | vec2(-0.5, -2.25) ];
+			input bool in4 = [ true | false | false | false | false | true | true | true | false | true ];
+			input bvec2 in5 = [ bvec2(false, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) | bvec2(true, false) ];
+			output mat4x2 out0 = [ mat4x2(0.0, 36.8125, -66.0, -0.75, -0.0322580645161, 1.0, 0.0, 0.0) | mat4x2(0.0, -8.25, 1.0, -0.75, -0.0322580645161, 0.0, 0.0, 1.0) | mat4x2(1.0, 3.5, -192.0, -32.0, 64.0, 0.0, 0.0, 0.0) | mat4x2(1.0, 1.0, 2.0, 0.0, 0.5, 0.0, 1.0, 1.0) | mat4x2(1.0, 2.0, 11.0, 1.0, 1.25, 0.0, 1.0, 0.0) | mat4x2(0.0, -0.5, 0.0, 1.0, 1.25, 1.0, 0.0, 1.0) | mat4x2(0.0, 0.0, 255.0, -0.5, -2.25, 1.0, 0.0, 0.0) | mat4x2(1.0, 1.0, 8.0, -32.0, 64.0, 1.0, 1.0, 1.0) | mat4x2(0.0, -20.125, 5.0, 0.0, 0.5, 0.0, 0.0, 0.0) | mat4x2(1.0, 0.0, -12.0, -0.5, -2.25, 1.0, 1.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec2_int_vec4_to_mat4x2
+		version 310 es
+		values
+		{
+			input bool in0 = [ false | false | true | false | true | false | true | true | true | false ];
+			input bvec2 in1 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, false) | bvec2(false, true) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(true, true) ];
+			input int in2 = [ -12 | 8 | 2 | 255 | 5 | -192 | 0 | 11 | 1 | -66 ];
+			input vec4 in3 = [ vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			output mat4x2 out0 = [ mat4x2(0.0, 1.0, 0.0, -12.0, 1.0, 1.25, 1.125, 1.75) | mat4x2(0.0, 0.0, 0.0, 8.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat4x2(1.0, 0.0, 0.0, 2.0, -32.0, 64.0, -51.0, 24.0) | mat4x2(0.0, 0.0, 0.0, 255.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat4x2(1.0, 1.0, 0.0, 5.0, -0.5, -2.25, -4.875, 9.0) | mat4x2(0.0, 0.0, 1.0, -192.0, -0.5, -2.25, -4.875, 9.0) | mat4x2(1.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.75, 0.825) | mat4x2(1.0, 0.0, 1.0, 11.0, -32.0, 64.0, -51.0, 24.0) | mat4x2(1.0, 1.0, 1.0, 1.0, 1.0, 1.25, 1.125, 1.75) | mat4x2(0.0, 1.0, 1.0, -66.0, 0.0, 0.5, 0.75, 0.825) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bvec4_ivec2_bool_to_mat4x2
+		version 310 es
+		values
+		{
+			input float in0 = [ 1.0 | -8.25 | -20.125 | 3.5 | -0.5 | 2.0 | 36.8125 | 0.0 ];
+			input bvec4 in1 = [ bvec4(false, false, false, true) | bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(false, true, false, false) | bvec4(false, false, false, false) | bvec4(true, false, false, true) | bvec4(false, true, false, false) | bvec4(false, false, false, true) ];
+			input ivec2 in2 = [ ivec2(-32, 64) | ivec2(0, -2) | ivec2(0, 0) | ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(1, 1) | ivec2(0, 0) ];
+			input bool in3 = [ true | true | false | true | true | false | false | false ];
+			output mat4x2 out0 = [ mat4x2(1.0, 0.0, 0.0, 0.0, 1.0, -32.0, 64.0, 1.0) | mat4x2(-8.25, 1.0, 0.0, 0.0, 1.0, 0.0, -2.0, 1.0) | mat4x2(-20.125, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0) | mat4x2(3.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4x2(-0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat4x2(2.0, 1.0, 0.0, 0.0, 1.0, 0.0, -2.0, 0.0) | mat4x2(36.8125, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0) | mat4x2(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x2(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_vec4_vec4_to_mat4x3
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) ];
+			input vec4 in1 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			input vec4 in2 = [ vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output mat4x3 out0 = [ mat4x3(-0.5, -2.25, -4.875, 9.0, 0.0, 0.5, 0.75, 0.825, -32.0, 64.0, -51.0, 24.0) | mat4x3(1.0, 1.25, 1.125, 1.75, -0.5, -2.25, -4.875, 9.0, 1.0, 1.25, 1.125, 1.75) | mat4x3(0.0, 0.5, 0.75, 0.825, -32.0, 64.0, -51.0, 24.0, -0.5, -2.25, -4.875, 9.0) | mat4x3(-0.75, -0.0322580645161, 0.0526315789474, 0.25, 1.0, 1.25, 1.125, 1.75, 0.0, 0.5, 0.75, 0.825) | mat4x3(-32.0, 64.0, -51.0, 24.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, -0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_ivec4_ivec4_to_mat4x3
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			input ivec4 in1 = [ ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) | ivec4(0, -2, -4, 9) | ivec4(1, 1, 1, 1) ];
+			input ivec4 in2 = [ ivec4(-32, 64, -51, 24) | ivec4(0, -2, -4, 9) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, 0) ];
+			output mat4x3 out0 = [ mat4x3(1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0) | mat4x3(0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0, 0.0, -2.0, -4.0, 9.0) | mat4x3(0.0, -2.0, -4.0, 9.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0) | mat4x3(-32.0, 64.0, -51.0, 24.0, 0.0, -2.0, -4.0, 9.0, 0.0, 0.0, 0.0, 0.0) | mat4x3(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec2_ivec2_float_float_float_int_int_bool_bool_bool_to_mat4x3
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(-0.5, -2.25) | vec2(0.0, 0.5) | vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(1.0, 1.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			input ivec2 in1 = [ ivec2(0, -2) | ivec2(-32, 64) | ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, 0) | ivec2(0, -2) | ivec2(0, 0) | ivec2(1, 1) ];
+			input float in2 = [ -20.125 | 3.5 | 2.0 | -0.5 | -8.25 | 0.0 | 1.0 | 0.0 | 1.0 | 36.8125 ];
+			input float in3 = [ 0.0 | -8.25 | 36.8125 | 1.0 | 0.0 | -20.125 | 3.5 | 2.0 | -0.5 | 1.0 ];
+			input float in4 = [ 0.0 | 1.0 | 3.5 | -20.125 | 0.0 | 36.8125 | 1.0 | -8.25 | 2.0 | -0.5 ];
+			input int in5 = [ 2 | 8 | 1 | -192 | 0 | -12 | 11 | 255 | 5 | -66 ];
+			input int in6 = [ 2 | -12 | 5 | 8 | 11 | 255 | 0 | -66 | 1 | -192 ];
+			input bool in7 = [ true | true | false | true | false | false | false | true | false | true ];
+			input bool in8 = [ true | false | false | true | true | false | true | true | false | false ];
+			input bool in9 = [ false | true | false | false | false | false | true | true | true | true ];
+			output mat4x3 out0 = [ mat4x3(-0.5, -2.25, 0.0, -2.0, -20.125, 0.0, 0.0, 2.0, 2.0, 1.0, 1.0, 0.0) | mat4x3(0.0, 0.5, -32.0, 64.0, 3.5, -8.25, 1.0, 8.0, -12.0, 1.0, 0.0, 1.0) | mat4x3(0.0, 0.5, 1.0, 1.0, 2.0, 36.8125, 3.5, 1.0, 5.0, 0.0, 0.0, 0.0) | mat4x3(1.0, 1.25, -32.0, 64.0, -0.5, 1.0, -20.125, -192.0, 8.0, 1.0, 1.0, 0.0) | mat4x3(-0.75, -0.0322580645161, 0.0, 0.0, -8.25, 0.0, 0.0, 0.0, 11.0, 0.0, 1.0, 0.0) | mat4x3(-0.5, -2.25, 0.0, 0.0, 0.0, -20.125, 36.8125, -12.0, 255.0, 0.0, 0.0, 0.0) | mat4x3(-32.0, 64.0, 0.0, 0.0, 1.0, 3.5, 1.0, 11.0, 0.0, 0.0, 1.0, 1.0) | mat4x3(1.0, 1.25, 0.0, -2.0, 0.0, 2.0, -8.25, 255.0, -66.0, 1.0, 1.0, 1.0) | mat4x3(-32.0, 64.0, 0.0, 0.0, 1.0, -0.5, 2.0, 5.0, 1.0, 0.0, 0.0, 1.0) | mat4x3(-0.75, -0.0322580645161, 1.0, 1.0, 36.8125, 1.0, -0.5, -66.0, -192.0, 1.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2, in3, in4, in5, in6, in7, in8, in9);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_float_int_vec3_bool_bvec3_float_bool_to_mat4x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | false | false | true | true | true | false | false | false ];
+			input float in1 = [ -8.25 | 2.0 | 1.0 | -0.5 | 0.0 | 0.0 | 36.8125 | -20.125 | 3.5 | 1.0 ];
+			input int in2 = [ 255 | 2 | 11 | 1 | 8 | -192 | 0 | -66 | -12 | 5 ];
+			input vec3 in3 = [ vec3(-0.75, -0.0322580645161, 0.0526315789474) | vec3(0.0, 0.5, 0.75) | vec3(0.0, 0.5, 0.75) | vec3(-32.0, 64.0, -51.0) | vec3(-0.5, -2.25, -4.875) | vec3(1.0, 1.25, 1.125) | vec3(-32.0, 64.0, -51.0) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			input bool in4 = [ true | true | false | false | true | false | false | false | true | true ];
+			input bvec3 in5 = [ bvec3(false, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, false, false) | bvec3(true, false, false) | bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) ];
+			input float in6 = [ 1.0 | 0.0 | -0.5 | 36.8125 | 1.0 | -20.125 | 2.0 | 0.0 | -8.25 | 3.5 ];
+			input bool in7 = [ true | true | false | false | false | false | true | true | false | true ];
+			output mat4x3 out0 = [ mat4x3(1.0, -8.25, 255.0, -0.75, -0.0322580645161, 0.0526315789474, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0) | mat4x3(1.0, 2.0, 2.0, 0.0, 0.5, 0.75, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0) | mat4x3(0.0, 1.0, 11.0, 0.0, 0.5, 0.75, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0) | mat4x3(0.0, -0.5, 1.0, -32.0, 64.0, -51.0, 0.0, 0.0, 1.0, 0.0, 36.8125, 0.0) | mat4x3(1.0, 0.0, 8.0, -0.5, -2.25, -4.875, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0) | mat4x3(1.0, 0.0, -192.0, 1.0, 1.25, 1.125, 0.0, 1.0, 0.0, 0.0, -20.125, 0.0) | mat4x3(1.0, 36.8125, 0.0, -32.0, 64.0, -51.0, 0.0, 1.0, 1.0, 1.0, 2.0, 1.0) | mat4x3(0.0, -20.125, -66.0, 1.0, 1.25, 1.125, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0) | mat4x3(0.0, 3.5, -12.0, -0.5, -2.25, -4.875, 1.0, 0.0, 0.0, 0.0, -8.25, 0.0) | mat4x3(0.0, 1.0, 5.0, -0.75, -0.0322580645161, 0.0526315789474, 1.0, 0.0, 0.0, 0.0, 3.5, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2, in3, in4, in5, in6, in7);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec4_int_vec4_bool_float_to_mat4x3
+		version 310 es
+		values
+		{
+			input bool in0 = [ true | true | true | false | true | false | false | true | false | false ];
+			input bvec4 in1 = [ bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(true, false, false, true) | bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, false, false, false) | bvec4(false, false, false, true) ];
+			input int in2 = [ 5 | 11 | 0 | -192 | -66 | 255 | 1 | -12 | 8 | 2 ];
+			input vec4 in3 = [ vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input bool in4 = [ false | true | true | false | true | false | true | true | false | false ];
+			input float in5 = [ -20.125 | 0.0 | 1.0 | -0.5 | 3.5 | -8.25 | 0.0 | 1.0 | 2.0 | 36.8125 ];
+			output mat4x3 out0 = [ mat4x3(1.0, 0.0, 0.0, 0.0, 0.0, 5.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 0.0, -20.125) | mat4x3(1.0, 0.0, 1.0, 0.0, 0.0, 11.0, -32.0, 64.0, -51.0, 24.0, 1.0, 0.0) | mat4x3(1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.25, 1.125, 1.75, 1.0, 1.0) | mat4x3(0.0, 1.0, 1.0, 1.0, 1.0, -192.0, -0.5, -2.25, -4.875, 9.0, 0.0, -0.5) | mat4x3(1.0, 1.0, 1.0, 1.0, 1.0, -66.0, 1.0, 1.25, 1.125, 1.75, 1.0, 3.5) | mat4x3(0.0, 1.0, 0.0, 0.0, 1.0, 255.0, -32.0, 64.0, -51.0, 24.0, 0.0, -8.25) | mat4x3(0.0, 1.0, 0.0, 0.0, 1.0, 1.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, 1.0, 0.0) | mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, -12.0, -0.5, -2.25, -4.875, 9.0, 1.0, 1.0) | mat4x3(0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.5, 0.75, 0.825, 0.0, 2.0) | mat4x3(0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 0.0, 0.5, 0.75, 0.825, 0.0, 36.8125) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_bvec4_ivec4_bool_bool_int_to_mat4x3
+		version 310 es
+		values
+		{
+			input float in0 = [ 36.8125 | -0.5 | 3.5 | 2.0 | 1.0 | -20.125 | 0.0 | 0.0 | -8.25 | 1.0 ];
+			input bvec4 in1 = [ bvec4(false, false, false, false) | bvec4(false, false, false, true) | bvec4(true, false, false, true) | bvec4(false, true, false, false) | bvec4(false, false, false, false) | bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, true, false, false) | bvec4(false, false, false, true) ];
+			input ivec4 in2 = [ ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(0, -2, -4, 9) ];
+			input bool in3 = [ false | true | false | true | false | false | false | true | true | true ];
+			input bool in4 = [ false | true | false | true | false | true | false | false | true | true ];
+			input int in5 = [ 2 | 1 | 8 | 11 | 255 | 5 | 0 | -66 | -192 | -12 ];
+			output mat4x3 out0 = [ mat4x3(36.8125, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 2.0) | mat4x3(-0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0) | mat4x3(3.5, 1.0, 0.0, 0.0, 1.0, -32.0, 64.0, -51.0, 24.0, 0.0, 0.0, 8.0) | mat4x3(2.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 11.0) | mat4x3(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0) | mat4x3(-20.125, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 5.0) | mat4x3(0.0, 1.0, 1.0, 1.0, 1.0, -32.0, 64.0, -51.0, 24.0, 0.0, 0.0, 0.0) | mat4x3(0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -66.0) | mat4x3(-8.25, 0.0, 1.0, 0.0, 0.0, 0.0, -2.0, -4.0, 9.0, 1.0, 1.0, -192.0) | mat4x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.0, -4.0, 9.0, 1.0, 1.0, -12.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4x3(in0, in1, in2, in3, in4, in5);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case vec4_vec4_vec4_vec4_to_mat4
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input vec4 in1 = [ vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input vec4 in2 = [ vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input vec4 in3 = [ vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.5, -2.25, -4.875, 9.0) ];
+			output mat4 out0 = [ mat4(-0.75, -0.0322580645161, 0.0526315789474, 0.25, -0.75, -0.0322580645161, 0.0526315789474, 0.25, -32.0, 64.0, -51.0, 24.0, -32.0, 64.0, -51.0, 24.0) | mat4(-32.0, 64.0, -51.0, 24.0, -32.0, 64.0, -51.0, 24.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, -0.75, -0.0322580645161, 0.0526315789474, 0.25) | mat4(-0.5, -2.25, -4.875, 9.0, -0.5, -2.25, -4.875, 9.0, -0.5, -2.25, -4.875, 9.0, 1.0, 1.25, 1.125, 1.75) | mat4(1.0, 1.25, 1.125, 1.75, 1.0, 1.25, 1.125, 1.75, 1.0, 1.25, 1.125, 1.75, 0.0, 0.5, 0.75, 0.825) | mat4(0.0, 0.5, 0.75, 0.825, 0.0, 0.5, 0.75, 0.825, 0.0, 0.5, 0.75, 0.825, -0.5, -2.25, -4.875, 9.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case ivec4_ivec4_ivec4_ivec4_to_mat4
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(-32, 64, -51, 24) | ivec4(0, -2, -4, 9) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, 0) ];
+			input ivec4 in1 = [ ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			input ivec4 in2 = [ ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) | ivec4(0, -2, -4, 9) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) ];
+			input ivec4 in3 = [ ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(0, 0, 0, 0) | ivec4(0, 0, 0, 0) | ivec4(-32, 64, -51, 24) ];
+			output mat4 out0 = [ mat4(-32.0, 64.0, -51.0, 24.0, 1.0, 1.0, 1.0, 1.0, -32.0, 64.0, -51.0, 24.0, 1.0, 1.0, 1.0, 1.0) | mat4(0.0, -2.0, -4.0, 9.0, 0.0, -2.0, -4.0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0, 9.0) | mat4(1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, -4.0, 9.0, 0.0, 0.0, 0.0, 0.0) | mat4(0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bvec4_bvec4_bvec4_bvec4_to_mat4
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(false, false, false, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(true, false, false, true) ];
+			input bvec4 in1 = [ bvec4(false, true, false, false) | bvec4(false, false, false, true) | bvec4(true, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			input bvec4 in2 = [ bvec4(false, true, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, true) | bvec4(true, false, false, true) ];
+			input bvec4 in3 = [ bvec4(true, true, true, true) | bvec4(false, false, false, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, false, false, true) ];
+			output mat4 out0 = [ mat4(0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0) | mat4(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0) | mat4(0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0) | mat4(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0) | mat4(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0, in1, in2, in3);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_ivec3_bvec3_vec4_ivec2_float_vec2_to_mat4
+		version 310 es
+		values
+		{
+			input float in0 = [ 2.0 | 1.0 | 3.5 | 0.0 | -20.125 | 36.8125 | -0.5 | -8.25 ];
+			input ivec3 in1 = [ ivec3(0, 0, 0) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(0, 0, 0) | ivec3(0, -2, -4) ];
+			input bvec3 in2 = [ bvec3(true, false, false) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(false, false, false) | bvec3(false, true, false) ];
+			input vec4 in3 = [ vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(0.0, 0.5, 0.75, 0.825) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(0.0, 0.5, 0.75, 0.825) ];
+			input ivec2 in4 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(0, 0) | ivec2(1, 1) | ivec2(-32, 64) | ivec2(0, 0) | ivec2(0, -2) ];
+			input float in5 = [ 2.0 | 3.5 | 36.8125 | -8.25 | 0.0 | -20.125 | 1.0 | -0.5 ];
+			input vec2 in6 = [ vec2(0.0, 0.5) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(0.0, 0.5) | vec2(-0.75, -0.0322580645161) | vec2(-0.5, -2.25) | vec2(1.0, 1.25) | vec2(1.0, 1.25) ];
+			output mat4 out0 = [ mat4(2.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -0.5, -2.25, -4.875, 9.0, 0.0, 0.0, 2.0, 0.0, 0.5) | mat4(1.0, -32.0, 64.0, -51.0, 1.0, 1.0, 1.0, 1.0, 1.25, 1.125, 1.75, 1.0, 1.0, 3.5, -0.5, -2.25) | mat4(3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.75, 0.825, 0.0, -2.0, 36.8125, -32.0, 64.0) | mat4(0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, -0.5, -2.25, -4.875, 9.0, 0.0, 0.0, -8.25, 0.0, 0.5) | mat4(-20.125, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.25, 1.125, 1.75, 1.0, 1.0, 0.0, -0.75, -0.0322580645161) | mat4(36.8125, 0.0, -2.0, -4.0, 0.0, 1.0, 0.0, -0.75, -0.0322580645161, 0.0526315789474, 0.25, -32.0, 64.0, -20.125, -0.5, -2.25) | mat4(-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -32.0, 64.0, -51.0, 24.0, 0.0, 0.0, 1.0, 1.0, 1.25) | mat4(-8.25, 0.0, -2.0, -4.0, 0.0, 1.0, 0.0, 0.0, 0.5, 0.75, 0.825, 0.0, -2.0, -0.5, 1.0, 1.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = mat4(in0, in1, in2, in3, in4, in5, in6);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # matrix_combine
diff --git a/external/vulkancts/data/vulkan/glsl/es310/functions.test b/external/vulkancts/data/vulkan/glsl/es310/functions.test
new file mode 100644
index 0000000..d3f34b3
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/functions.test
@@ -0,0 +1,3134 @@
+# Tests todo:
+# - inout with varyings, attributes, uniforms (and arrays of 'em)
+# - inout with arrays, array elements
+# - inout with array elements
+# - inout by-value semantics (arrays & elements & structs)
+
+# Done:
+# - control flow: return, return in loop, etc.
+
+group datatypes "Function Parameter Data Types"
+
+	case float_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				return -a;
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_vec2
+		version 310 es
+		values
+		{
+			input vec2 in0		= [ vec2(0.0, 1.0) | vec2(2.0, 2.5) ];
+			output float out0	= [ -1.0 | -4.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (vec2 a)
+			{
+				return -(a.x + a.y);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_vec3
+		version 310 es
+		values
+		{
+			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
+			output float out0	= [ 1.0 | -0.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (vec3 a)
+			{
+				return -(a.x + a.y + a.z);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_vec4
+		version 310 es
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (vec4 a)
+			{
+				return -(a.x + a.y + a.z + a.w);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_mat2
+		version 310 es
+		values
+		{
+			input mat2 in0		= [ mat2(0.0, 1.0, -2.0, 0.5) | mat2(2.0, 2.5, 4.0, -7.0) ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (mat2 a)
+			{
+				return -(a[0][0] + a[0][1] + a[1][0] + a[1][1]);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_mat3
+		version 310 es
+		values
+		{
+			input mat3 in0		= [ mat3(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0) | mat3(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0) ];
+			output float out0	= [ -4.5 | -5.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (mat3 a)
+			{
+				return -(a[0][0] + a[0][1] + a[0][2] + a[1][0] + a[1][1] + a[1][2] + a[2][0] + a[2][1] + a[2][2]);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_mat4
+		version 310 es
+		values
+		{
+			input mat4 in0		= [ mat4(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -2.0, -2.0) | mat4(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0, 0.0, 2.0, -1.0, 1.0, 0.0, -1.0, 3.0) ];
+			output float out0	= [ -5.5 | -9.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (mat4 a)
+			{
+				return -(a[0][0] + a[0][1] + a[0][2] + a[0][3] + a[1][0] + a[1][1] + a[1][2] + a[1][3] + a[2][0] + a[2][1] + a[2][2] + a[2][3] + a[3][0] + a[3][1] + a[3][2] + a[3][3]);
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_int
+		version 310 es
+		values
+		{
+			input int in0		= [ -1 | 0 | 1 | 4 ];
+			output int out0		= [ 1 | 0 | -1 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (int a)
+			{
+				return -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec2
+		version 310 es
+		values
+		{
+			input ivec2 in0		= [ ivec2(-1, 0) | ivec2(1, 4) ];
+			output int out0		= [ 1 | -5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (ivec2 a)
+			{
+				return -(a.x + a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec3
+		version 310 es
+		values
+		{
+			input ivec3 in0		= [ ivec3(-1, 0, 2) | ivec3(1, 4, -8) ];
+			output int out0		= [ -1 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (ivec3 a)
+			{
+				return -(a.x + a.y + a.z);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case int_ivec4
+		version 310 es
+		values
+		{
+			input ivec4 in0		= [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
+			output int out0		= [ -3 | 1 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (ivec4 a)
+			{
+				return -(a.x + a.y + a.z + a.w);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uint
+		version 310 es
+		values
+		{
+			input uint in0		= [ 1 | 0 | 2 | 4 ];
+			output uint out0	= [ 1 | 0 | 4 | 16 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			uint func (uint a)
+			{
+				return a*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uvec2
+		version 310 es
+		values
+		{
+			input uvec2 in0		= [ uvec2(1, 0) | uvec2(2, 4) ];
+			output uint out0	= [ 1 | 6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			uint func (uvec2 a)
+			{
+				return (a.x + a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uvec3
+		version 310 es
+		values
+		{
+			input uvec3 in0		= [ uvec3(1, 0, 2) | uvec3(1, 4, 8) ];
+			output uint out0		= [ 3 | 13 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			uint func (uvec3 a)
+			{
+				return (a.x + a.y + a.z);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case uint_uvec4
+		version 310 es
+		values
+		{
+			input uvec4 in0		= [ uvec4(1, 0, 2, 2) | uvec4(1, 4, 8, 2) ];
+			output uint out0	= [ 5 | 15 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			uint func (uvec4 a)
+			{
+				return (a.x + a.y + a.z + a.w);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bool
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (bool a)
+			{
+				return !a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec2
+		version 310 es
+		values
+		{
+			input bvec2 in0		= [ bvec2(true, true) | bvec2(false, true) ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (bvec2 a)
+			{
+				return !(a.x == a.y);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec3
+		version 310 es
+		values
+		{
+			input bvec3 in0		= [ bvec3(true, true, false) | bvec3(true, false, false) ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (bvec3 a)
+			{
+				return (a.x == a.y) == a.z;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case bool_bvec4
+		version 310 es
+		values
+		{
+			input bvec4 in0		= [ bvec4(true, true, true, false) | bvec4(false, false, true, true) | bvec4(true, false, false, true) ];
+			output bool out0	= [ false | true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (bvec4 a)
+			{
+				return ((a.x == a.y) == (a.z == a.w));
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mat2
+		version 310 es
+		values
+		{
+			input mat2 in0	= [ mat2(-2.0, 0.5, -1.0, 1.0) | mat2(1.0, -3.5, -3.5, 2.5) | mat2(-2.0, -2.0, 3.5, 0.0) ];
+			output mat2 out0	= [ mat2(4.0, -1.0, 2.0, -2.0) | mat2(-2.0, 7.0, 7.0, -5.0) | mat2(4.0, 4.0, -7.0, -0.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat2 func (mat2 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat2x3
+		version 310 es
+		values
+		{
+			input mat2x3 in0	= [ mat2x3(2.5, 0.0, 1.0, -2.5, 1.0, 3.0) | mat2x3(0.0, 2.0, 1.5, -3.5, 2.0, 0.5) | mat2x3(-1.5, -3.5, 2.5, 0.0, 1.5, 3.0) ];
+			output mat2x3 out0	= [ mat2x3(-5.0, -0.0, -2.0, 5.0, -2.0, -6.0) | mat2x3(-0.0, -4.0, -3.0, 7.0, -4.0, -1.0) | mat2x3(3.0, 7.0, -5.0, -0.0, -3.0, -6.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat2x3 func (mat2x3 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat2x4
+		version 310 es
+		values
+		{
+			input mat2x4 in0	= [ mat2x4(1.5, 3.0, -1.0, 2.5, -0.5, 3.5, 3.0, -3.0) | mat2x4(-2.5, -2.0, 3.5, -0.5, 1.0, -1.5, 0.0, -1.0) | mat2x4(-1.0, 0.5, 0.5, 3.0, 1.5, 3.0, 2.5, 3.5) ];
+			output mat2x4 out0	= [ mat2x4(-3.0, -6.0, 2.0, -5.0, 1.0, -7.0, -6.0, 6.0) | mat2x4(5.0, 4.0, -7.0, 1.0, -2.0, 3.0, -0.0, 2.0) | mat2x4(2.0, -1.0, -1.0, -6.0, -3.0, -6.0, -5.0, -7.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat2x4 func (mat2x4 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat3x2
+		version 310 es
+		values
+		{
+			input mat3x2 in0	= [ mat3x2(1.5, -2.5, 2.5, 3.5, 3.0, 0.5) | mat3x2(1.5, -2.0, 2.5, 0.5, -1.5, -3.5) | mat3x2(2.5, 3.5, -3.0, 2.5, -0.5, -2.5) ];
+			output mat3x2 out0	= [ mat3x2(-3.0, 5.0, -5.0, -7.0, -6.0, -1.0) | mat3x2(-3.0, 4.0, -5.0, -1.0, 3.0, 7.0) | mat3x2(-5.0, -7.0, 6.0, -5.0, 1.0, 5.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3x2 func (mat3x2 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat3
+		version 310 es
+		values
+		{
+			input mat3 in0	= [ mat3(-1.5, 2.0, 3.0, -3.5, 1.0, -3.5, 1.5, -1.5, 3.0) | mat3(3.5, 0.0, 3.5, -1.5, -3.0, 0.5, -3.5, -2.5, -0.5) | mat3(1.0, -2.5, -3.5, 3.0, -1.5, 3.5, 3.0, -1.0, -0.5) ];
+			output mat3 out0	= [ mat3(3.0, -4.0, -6.0, 7.0, -2.0, 7.0, -3.0, 3.0, -6.0) | mat3(-7.0, -0.0, -7.0, 3.0, 6.0, -1.0, 7.0, 5.0, 1.0) | mat3(-2.0, 5.0, 7.0, -6.0, 3.0, -7.0, -6.0, 2.0, 1.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3 func (mat3 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat3x4
+		version 310 es
+		values
+		{
+			input mat3x4 in0	= [ mat3x4(0.0, 1.0, 0.5, 0.5, 1.0, 3.5, 0.0, -0.5, 1.5, -2.0, -1.5, 3.5) | mat3x4(0.0, 0.5, -3.5, -0.5, 0.5, -3.5, 1.0, 1.0, -3.5, 1.0, -0.5, 1.5) | mat3x4(-1.0, 1.5, 2.0, -3.5, -3.5, 1.5, 3.5, -2.0, -0.5, 0.5, -1.5, -1.0) ];
+			output mat3x4 out0	= [ mat3x4(-0.0, -2.0, -1.0, -1.0, -2.0, -7.0, -0.0, 1.0, -3.0, 4.0, 3.0, -7.0) | mat3x4(-0.0, -1.0, 7.0, 1.0, -1.0, 7.0, -2.0, -2.0, 7.0, -2.0, 1.0, -3.0) | mat3x4(2.0, -3.0, -4.0, 7.0, 7.0, -3.0, -7.0, 4.0, 1.0, -1.0, 3.0, 2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat3x4 func (mat3x4 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat4x2
+		version 310 es
+		values
+		{
+			input mat4x2 in0	= [ mat4x2(-1.5, -1.0, 0.5, -1.5, -1.0, 2.0, -3.5, 0.5) | mat4x2(2.0, -1.5, -2.0, 2.5, -2.0, -2.5, -0.5, 1.5) | mat4x2(-3.0, -1.5, -1.0, 2.5, -0.5, 2.5, -2.5, -1.0) ];
+			output mat4x2 out0	= [ mat4x2(3.0, 2.0, -1.0, 3.0, 2.0, -4.0, 7.0, -1.0) | mat4x2(-4.0, 3.0, 4.0, -5.0, 4.0, 5.0, 1.0, -3.0) | mat4x2(6.0, 3.0, 2.0, -5.0, 1.0, -5.0, 5.0, 2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat4x2 func (mat4x2 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat4x3
+		version 310 es
+		values
+		{
+			input mat4x3 in0	= [ mat4x3(1.0, 3.0, -0.5, -2.0, -3.0, 0.0, -2.5, 2.5, 2.5, -2.5, -1.5, 2.5) | mat4x3(1.0, 2.5, -1.0, -3.0, -1.5, 2.0, -1.5, -1.0, -0.5, -0.5, -0.5, 3.0) | mat4x3(-2.5, -3.5, 3.5, 3.0, 3.5, -0.5, 3.5, 3.0, -2.0, 2.0, 2.5, 1.0) ];
+			output mat4x3 out0	= [ mat4x3(-2.0, -6.0, 1.0, 4.0, 6.0, -0.0, 5.0, -5.0, -5.0, 5.0, 3.0, -5.0) | mat4x3(-2.0, -5.0, 2.0, 6.0, 3.0, -4.0, 3.0, 2.0, 1.0, 1.0, 1.0, -6.0) | mat4x3(5.0, 7.0, -7.0, -6.0, -7.0, 1.0, -7.0, -6.0, 4.0, -4.0, -5.0, -2.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat4x3 func (mat4x3 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+
+	case mat4
+		version 310 es
+		values
+		{
+			input mat4 in0	= [ mat4(0.0, -1.5, -1.0, -2.0, -3.0, 0.5, -1.5, 2.5, -3.5, 3.0, 1.5, 3.0, 3.0, 3.0, 0.5, -3.5) | mat4(2.0, -2.5, -1.5, 1.0, 0.0, -0.5, 3.5, 1.0, -1.0, -2.0, 2.5, 0.0, 2.0, -1.0, -2.5, 0.5) | mat4(2.5, -2.5, 2.0, 3.0, 2.5, 2.5, -3.5, 1.0, 2.5, -3.5, -1.5, -1.5, 0.0, -0.5, 0.0, 2.0) ];
+			output mat4 out0	= [ mat4(-0.0, 3.0, 2.0, 4.0, 6.0, -1.0, 3.0, -5.0, 7.0, -6.0, -3.0, -6.0, -6.0, -6.0, -1.0, 7.0) | mat4(-4.0, 5.0, 3.0, -2.0, -0.0, 1.0, -7.0, -2.0, 2.0, 4.0, -5.0, -0.0, -4.0, 2.0, 5.0, -1.0) | mat4(-5.0, 5.0, -4.0, -6.0, -5.0, -5.0, 7.0, -2.0, -5.0, 7.0, 3.0, 3.0, -0.0, 1.0, -0.0, -4.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			mat4 func (mat4 a)
+			{
+				return -2.0*a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case float_struct
+		version 310 es
+		values
+		{
+			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
+			output float out0	= [ 1.0 | -0.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct Pos { float a, b, c; };
+
+			float func (Pos p)
+			{
+				return -(p.a + p.b + p.c);
+			}
+
+			void main()
+			{
+				Pos p = Pos(in0.x, in0.y, in0.z);
+				out0 = func(p);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct_struct
+		version 310 es
+		values
+		{
+			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
+			output float out0	= [ 1.0 | -0.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct Pos { float a, b, c; };
+
+			Pos func (Pos p)
+			{
+				return Pos(-p.a, -p.b, -p.c);
+			}
+
+			void main()
+			{
+				Pos p = Pos(in0.x, in0.y, in0.z);
+				p = func(p);
+				out0 = p.a + p.b + p.c;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case struct_nested_struct
+		version 310 es
+		values
+		{
+			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
+			output float out0	= [ 1.0 | -0.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct Pos { float a, b, c; };
+			struct Line { Pos start, end; };
+
+			Line func (Pos p)
+			{
+				return Line(p, Pos(-p.a, -p.b, -p.c));
+			}
+
+			float sum (Pos p)
+			{
+				return (p.a + p.b + p.c);
+			}
+
+			void main()
+			{
+				Pos p = Pos(in0.x, in0.y, in0.z);
+				Line line = func(p);
+				out0 = sum(line.start) + (2.0 * sum(line.end));
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # datatypes
+
+group qualifiers "Function Parameter Qualifiers"
+
+	case in_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (in float a)
+			{
+				a = -a;
+				return 2.0 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = in0;
+				float g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out float a)
+			{
+				a = -1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout float a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_lowp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (in lowp float a)
+			{
+				a = -a;
+				return 2.0 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = in0;
+				float g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_lowp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out lowp float a)
+			{
+				a = -1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_lowp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout lowp float a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_highp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (in highp float a)
+			{
+				a = -a;
+				return 2.0 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = in0;
+				float g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_highp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out highp float a)
+			{
+				a = -1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_highp_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout highp float a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = 1.0;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case const_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (const float a)
+			{
+				float b = -a;
+				return 2.0 * b;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = in0;
+				float g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case const_in_float
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (const in float a)
+			{
+				float b = -a;
+				return 2.0 * b;
+			}
+
+			void main()
+			{
+				${SETUP}
+				float f = in0;
+				float g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 4 ];
+			output int out0		= [ 0 | -1 | 2 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (in int a)
+			{
+				a = -a;
+				return 2 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = in0;
+				int g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out int a)
+			{
+				a = -1;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout int a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_lowp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 4 ];
+			output int out0		= [ 0 | -1 | 2 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (in lowp int a)
+			{
+				a = -a;
+				return 2 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = in0;
+				int g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_lowp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out lowp int a)
+			{
+				a = -1;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_lowp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout lowp int a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_highp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 4 ];
+			output int out0		= [ 0 | -1 | 2 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (in highp int a)
+			{
+				a = -a;
+				return 2 * a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = in0;
+				int g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_highp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (out highp int a)
+			{
+				a = -1;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_highp_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			void func (inout highp int a)
+			{
+				a = -a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = 1;
+				func(f);
+				out0 = f * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case const_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 4 ];
+			output int out0		= [ 0 | -1 | 2 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (const int a)
+			{
+				int b = -a;
+				return 2 * b;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = in0;
+				int g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case const_in_int
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 4 ];
+			output int out0		= [ 0 | -1 | 2 | -4 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (const in int a)
+			{
+				int b = -a;
+				return 2 * b;
+			}
+
+			void main()
+			{
+				${SETUP}
+				int f = in0;
+				int g = func(f);
+				out0 = f + g;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case in_bool
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (in bool a)
+			{
+				a = !a;
+				return a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool f = in0;
+				bool g = func(f);
+				out0 = (f != g);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case out_bool
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void func (out bool a)
+			{
+				a = false;
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool f = true;
+				func(f);
+				out0 = (in0 == f);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case inout_bool
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			void func (inout bool a)
+			{
+				a = !a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool f = true;
+				func(f);
+				out0 = (in0 == f);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case const_bool
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ true | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (const bool a)
+			{
+				bool b = !a;
+				return b;
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool f = in0;
+				bool g = func(f);
+				out0 = (f != g);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # qualifiers
+
+group declarations "Function Declarations"
+
+	case basic
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (void);
+
+			float func (void)
+			{
+				return -1.0;
+			}
+
+			void main()
+			{
+				out0 = func() * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case basic_arg
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float f);
+
+			float func (float f)
+			{
+				return -f;
+			}
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case define_after_use
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (void);
+
+			void main()
+			{
+				out0 = func() * in0;
+				${OUTPUT}
+			}
+
+			float func (void)
+			{
+				return -1.0;
+			}
+		""
+	end
+
+	case double_declare
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (void);
+
+			float func (void);
+
+			float func (void)
+			{
+				return -1.0;
+			}
+
+			void main()
+			{
+				out0 = func() * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case declare_after_define
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (void)
+			{
+				return -1.0;
+			}
+
+			float func (void);
+
+			void main()
+			{
+				out0 = func() * in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case void_vs_no_void
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func ();
+
+			void main()
+			{
+				out0 = func() * in0;
+				${OUTPUT}
+			}
+
+			float func (void)
+			{
+				return -1.0;
+			}
+		""
+	end
+
+	case in_vs_no_in
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float f);
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+
+			float func (in float f)
+			{
+				return -f;
+			}
+		""
+	end
+
+	case default_vs_explicit_precision
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float f);
+
+			void main()
+			{
+				out0 = func(in0);
+				${OUTPUT}
+			}
+
+			float func (mediump float f)
+			{
+				return -f;
+			}
+		""
+	end
+
+
+end # declarations
+
+group overloading "Function Overloading"
+
+	case user_func_arg_type_simple
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				return -a;
+			}
+
+			int func (int a)
+			{
+				return -a;
+			}
+
+			void main()
+			{
+				out0 = func(in0) * float(func(-1));
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arg_float_types
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (float a) { return -a; }
+			vec2 func (vec2 a) { return a.yx; }
+			vec3 func (vec3 a) { return a.xxx; }
+			vec4 func (vec4 a) { return a.wwww; }
+
+			void main()
+			{
+				out0 = func(func(func(func(vec4(in0)).xyz).xy).x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arg_int_types
+		version 310 es
+		values
+		{
+			input int in0		= [ 0 | 1 | -2 | 6 ];
+			output int out0		= [ 0 | -1 | 2 | -6 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (int a) { return -a; }
+			ivec2 func (ivec2 a) { return a.yx; }
+			ivec3 func (ivec3 a) { return a.xxx; }
+			ivec4 func (ivec4 a) { return a.wwww; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(func(func(func(ivec4(in0)).xyz).xy).x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arg_bool_types
+		version 310 es
+		values
+		{
+			input bool in0		= [ true | false ];
+			output bool out0	= [ false | true ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (bool a) { return !a; }
+			bvec2 func (bvec2 a) { return a.yx; }
+			bvec3 func (bvec3 a) { return a.xxx; }
+			bvec4 func (bvec4 a) { return a.wwww; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(func(func(func(bvec4(in0)).xyz).xy).x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arg_basic_types
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			float func (float a) { return -a; }
+			vec2 func (vec2 a) { return a.yx; }
+			vec3 func (vec3 a) { return a.xxx; }
+			vec4 func (vec4 a) { return a.wwww; }
+			int func (int a) { return -a; }
+			ivec2 func (ivec2 a) { return a.yx; }
+			ivec3 func (ivec3 a) { return a.xxx; }
+			ivec4 func (ivec4 a) { return a.wwww; }
+			bool func (bool a) { return !a; }
+			bvec2 func (bvec2 a) { return a.yx; }
+			bvec3 func (bvec3 a) { return a.xxx; }
+			bvec4 func (bvec4 a) { return a.wwww; }
+
+			void main()
+			{
+				${SETUP}
+				if (func(func(bvec4(false)).x))
+					out0 = func(in0) * float(func(-1));
+				else
+					out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arg_complex_types
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			struct Pos { float a, b, c; };
+			struct Line { Pos start, end; };
+
+			float func (float a) { return -a; }
+			float func (float a[4]) { return a[0] + a[3]; }
+			vec2 func (vec2 a) { return a.yx; }
+			vec3 func (vec3 a) { return a.xxx; }
+			vec4 func (vec4 a) { return a.wwww; }
+			vec4 func (vec4 a[4]) { return a[1] + a[2]; }
+			int func (int a) { return -a; }
+			ivec2 func (ivec2 a) { return a.yx; }
+			ivec3 func (ivec3 a) { return a.xxx; }
+			ivec4 func (ivec4 a) { return a.wwww; }
+			bool func (bool a) { return !a; }
+			bvec2 func (bvec2 a) { return a.yx; }
+			bvec3 func (bvec3 a) { return a.xxx; }
+			bvec4 func (bvec4 a) { return a.wwww; }
+			Pos func (Pos a) { return a; }
+			Line func (Line a) { return Line(a.end, a.start); }
+
+			void main()
+			{
+				${SETUP}
+				float arr[4];
+				vec4 arr2[4];
+				out0 = func(arr) + func(arr2).x;
+				if (func(func(bvec4(false)).x))
+					out0 = func(in0) * float(func(-1));
+				else
+					out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case user_func_arguments
+		version 310 es
+		values
+		{
+			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
+			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				return -a;
+			}
+
+			float func (float a, float b)
+			{
+				return a * b;
+			}
+
+			void main()
+			{
+				out0 = func(in0) * func(-0.5, -2.0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case array_size
+		version 310 es
+		values
+		{
+			output float out0	= [ 1.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float f[3])
+			{
+				return f[0];
+			}
+
+			float func (float f[4])
+			{
+				return f[1];
+			}
+
+			void main ()
+			{
+				${SETUP}
+				float[4] x = float[4] (-1.0, 1.0, 0.0, 0.0);
+				out0 = func(x);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # overloading
+
+group array_arguments "Arrays as Arguments"
+
+	case local_in_float
+		version 310 es
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (in float a[4])
+			{
+				a[0] = -1.0;
+				a[2] = -4.0;
+				a[3] = -3.0 * a[1];
+				return a[0];
+			}
+
+			void main()
+			{
+				float arr[4];
+				arr[0] = in0.x;
+				arr[1] = in0.y;
+				arr[2] = in0.z;
+				arr[3] = in0.w;
+				float f = func(arr);
+				out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case global_in_float
+		version 310 es
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (in float a[4])
+			{
+				a[0] = -1.0;
+				a[2] = -4.0;
+				a[3] = -3.0 * a[1];
+				return a[0];
+			}
+
+			float arr[4];
+
+			void main()
+			{
+				arr[0] = in0.x;
+				arr[1] = in0.y;
+				arr[2] = in0.z;
+				arr[3] = in0.w;
+				float f = func(arr);
+				out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case local_in_int
+		version 310 es
+		values
+		{
+			input ivec4 in0		= [ ivec4(0, 1, 2, -4) | ivec4(-7, -11, 13, 19) ];
+			output ivec4 out0	= [ ivec4(0, -1, -2, 4) | ivec4(7, 11, -13, -19) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (in int a[4])
+			{
+				a[0] = -1;
+				a[2] = -4;
+				a[3] = -3 * a[1];
+				return a[0];
+			}
+
+			void main()
+			{
+				${SETUP}
+				int arr[4];
+				arr[0] = in0.x;
+				arr[1] = in0.y;
+				arr[2] = in0.z;
+				arr[3] = in0.w;
+				int f = func(arr);
+				out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case global_in_int
+		version 310 es
+		values
+		{
+			input ivec4 in0		= [ ivec4(0, 1, 2, 4) | ivec4(-7, -11, 13, 19) ];
+			output ivec4 out0	= [ ivec4(0, -1, -2, -4) | ivec4(7, 11, -13, -19) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int func (in int a[4])
+			{
+				a[0] = -1;
+				a[2] = -4;
+				a[3] = -3 * a[1];
+				return a[0];
+			}
+
+			int arr[4];
+
+			void main()
+			{
+				${SETUP}
+				arr[0] = in0.x;
+				arr[1] = in0.y;
+				arr[2] = in0.z;
+				arr[3] = in0.w;
+				int f = func(arr);
+				out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+
+		""
+	end
+
+	case local_in_bool
+		version 310 es
+		values
+		{
+			input bvec4 in0		= [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0	= [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (in bool a[4])
+			{
+				a[0] = false;
+				a[2] = true;
+				a[3] = !a[1];
+				return a[0];
+			}
+
+			void main()
+			{
+				${SETUP}
+				bool arr[4];
+				arr[0] = !in0.x;
+				arr[1] = !in0.y;
+				arr[2] = !in0.z;
+				arr[3] = !in0.w;
+				func(arr);
+				out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case global_in_bool
+		version 310 es
+		values
+		{
+			input bvec4 in0		= [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0	= [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			bool func (in bool a[4])
+			{
+				a[0] = false;
+				a[2] = true;
+				a[3] = !a[1];
+				return a[0];
+			}
+
+			bool arr[4];
+
+			void main()
+			{
+				${SETUP}
+				arr[0] = !in0.x;
+				arr[1] = !in0.y;
+				arr[2] = !in0.z;
+				arr[3] = !in0.w;
+				func(arr);
+				out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case test_helpers
+		version 310 es
+		desc "Check that helper functions are supported properly."
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output float out0	= [ 1.0 | 1.0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec4 get (in float arr[4]);
+			void set (out float arr[4], vec4 val);
+			void negate (inout float arr[4]);
+			bool test (in float arr[4], vec4 ref);
+			bool isEqual (in float a[4], in float b[4]);
+
+			void main()
+			{
+				float arr[4];
+				set(arr, in0);
+				negate(arr);
+				out0 = float(test(arr, -in0));
+				${OUTPUT}
+			}
+
+			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+		""
+	end
+
+	case copy_local_in_on_call
+		version 310 es
+		desc "Check that local 'in' arguments are copied on call and don't alias."
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec4 get (in float arr[4]);
+			void set (out float arr[4], vec4 val);
+			void negate (inout float arr[4]);
+			bool test (in float arr[4], vec4 ref);
+			bool isEqual (in float a[4], in float b[4]);
+
+			float func (in float a[4], in float b[4])
+			{
+				a[0] = 2.123;
+				a[2] = -4.123;
+				return isEqual(a, b) ? 1.0 : -1.0;
+			}
+
+			void main()
+			{
+				float arr[4];
+				set(arr, in0);
+				out0 = in0 * func(arr, arr);
+				${OUTPUT}
+			}
+
+			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+		""
+	end
+
+	case copy_global_in_on_call
+		version 310 es
+		desc "Check that global 'in' arguments are copied on call and don't alias."
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec4 get (in float arr[4]);
+			void set (out float arr[4], vec4 val);
+			void negate (inout float arr[4]);
+			bool test (in float arr[4], vec4 ref);
+			bool isEqual (in float a[4], in float b[4]);
+
+			float func (in float a[4], in float b[4])
+			{
+				a[0] = 2.123;
+				a[2] = -4.123;
+				return isEqual(a, b) ? 1.0 : -1.0;
+			}
+
+			float arr[4];
+
+			void main()
+			{
+				set(arr, in0);
+				out0 = in0 * func(arr, arr);
+				${OUTPUT}
+			}
+
+			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+		""
+	end
+
+	case copy_local_inout_on_call
+		version 310 es
+		desc "Check that local 'in' arguments are copied on call and don't alias."
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec4 get (in float arr[4]);
+			void set (out float arr[4], vec4 val);
+			void negate (inout float arr[4]);
+			bool test (in float arr[4], vec4 ref);
+			bool isEqual (in float a[4], in float b[4]);
+
+			float func (inout float a[4], inout float b[4])
+			{
+				negate(a);
+				return isEqual(a, b) ? 1.0 : -1.0;
+			}
+
+			void main()
+			{
+				float arr[4];
+				set(arr, in0);
+				float m = func(arr, arr); // returns -1.0
+				float n = float(test(arr, in0) || test(arr, -in0));
+				out0 = in0 * m * n;
+				${OUTPUT}
+			}
+
+			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+		""
+	end
+
+	case copy_global_inout_on_call
+		version 310 es
+		desc "Check that global 'in' arguments are copied on call and don't alias."
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
+			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			vec4 get (in float arr[4]);
+			void set (out float arr[4], vec4 val);
+			void negate (inout float arr[4]);
+			bool test (in float arr[4], vec4 ref);
+			bool isEqual (in float a[4], in float b[4]);
+
+			float func (in float a[4], in float b[4])
+			{
+				negate(a);
+				return isEqual(a, b) ? 1.0 : -1.0;
+			}
+
+			float arr[4];
+
+			void main()
+			{
+				set(arr, in0);
+				float m = func(arr, arr); // returns -1.0
+				float n = float(test(arr, in0) || test(arr, -in0));
+				out0 = in0 * m * n;
+				${OUTPUT}
+			}
+
+			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+		""
+	end
+
+#			vec4 get (in float arr[4]);
+#			void set (out float arr[4], vec4 val);
+#			void negate (inout float arr[4]);
+#			bool test (in float arr[4], vec4 ref);
+#			bool isEqual (in float a[4], in float b[4]);
+
+#			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
+#			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
+#			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
+#			void negate (inout float arr[4]) { set(arr, -get(arr)); }
+#			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
+#			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
+
+end # array_arguments
+
+#group qualifiers "Function Parameter Qualifiers"
+#
+#end # qualifiers
+
+group control_flow "Control Flow In Functions"
+
+	case simple_return
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				return -a;
+				a = a * -1.0;
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_in_if
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				if (a != 0.0)
+					return -a;
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_in_else
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				if (a == 0.0)
+					return 1.0;
+				else
+					return -a;
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_in_loop
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				while (a < 100.0)
+					return -a;
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_in_loop_if
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				while (a < 100.0)
+				{
+					a = -a;
+					if (a != 0.0)
+						return a;
+					else
+						return -1.0;
+				}
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_after_loop
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				for (int i = 0; i < 5; i++)
+					a = -a;
+				return a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_after_break
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				for (int i = 0; i < 6; i++)
+				{
+					a = -a;
+					if (i == 4)
+						break;
+				}
+				return a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_after_continue
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				for (int i = 0; i < 6; i++)
+				{
+					if (i == 4)
+						continue;
+					a = -a;
+				}
+				return a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_in_nested_loop
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				for (int i = 0; i < 6; i++)
+				{
+					a = -a;
+					for (int j = 0; j < 4; j++)
+					{
+						a = -a;
+						if (i == 1)
+							return a;
+					}
+					if (i == 4)
+						return 1.0;
+				}
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case return_after_loop_sequence
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				int i;
+				for (i = 0; i < 6; i++) // negate a
+				{
+					a = -a;
+					if (i == 4)
+						a = -a;
+				}
+
+				for (; i < 10; i++) // keep a
+				{
+					if (i == 8)
+						continue;
+					else if (i == 9)
+						break;
+					a = -a;
+				}
+
+				return a;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mixed_return_break_continue
+		version 310 es
+		values
+		{
+			input float in0		= [ -0.5 | 1.5 ];
+			output float out0	= [ 0.5 | -1.5 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float func (float a)
+			{
+				int i;
+				for (i = 0; i < 6; i++)
+				{
+					if (i == 0)
+						continue;
+					else if (i == 1)
+					{
+					}
+					else if (i == 3)
+						break;
+					else
+						return a;
+					a = -a;
+				}
+
+				return 1.0;
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # control_flow
+
+group misc "Miscellaneous"
+
+	case multi_arg_float
+		version 310 es
+		values
+		{
+			input vec4 in0		= [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
+			output float out0	= [ 0.5 | -1.5 ]; # -sum(in0)
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			float sum(vec4 v) { return (v.x + v.y + v.z + v.w); }
+
+			float func (float a, vec3 b, vec2 c, vec2 d, vec4 e)
+			{
+				return -sum(vec4(a, b) + vec4(c, d)) + sum(e);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case multi_arg_int
+		version 310 es
+		values
+		{
+			input ivec4 in0		= [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
+			output int out0		= [ -3 | 1 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			precision mediump int;
+			${DECLARATIONS}
+
+			int sum(ivec4 v) { return (v.x + v.y + v.z + v.w); }
+
+			int func (int a, ivec3 b, ivec2 c, ivec2 d, ivec4 e)
+			{
+				return -sum(ivec4(a, b) + ivec4(c, d)) + sum(e);
+			}
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case argument_eval_order_1
+		version 310 es
+		values
+		{
+			input int in0	= [  0 | 1 | 3 | 5 ];
+			output int out0	= [ -1 | 5 | 11 | 17 ];
+		}
+
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			int func (float a, int b, bool c, int d)
+			{
+				if (c)
+					return b + int(a) + d;
+				else
+					return -1;
+			}
+
+			void main ()
+			{
+				${SETUP}
+				float v0 = float(in0);
+				int v1 = in0;
+				out0 = func((v0 += 1.0), v1++, (v0 > 1.5), v1);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case argument_eval_order_2
+		version 310 es
+		values
+		{
+			input int in0	= [ 0 | -1 | 3 | 5 ];
+			output int out0	= [ 3 | -1 | 9 | 13 ];
+		}
+
+		both ""
+			#version 310 es
+			precision highp float;
+			${DECLARATIONS}
+
+			int g;
+
+			int modG (int v)
+			{
+				g += v;
+				return v;
+			}
+
+			int func (float a, int b, bool c, int d)
+			{
+				if (c)
+					return b + int(a) + d;
+				else
+					return -1;
+			}
+
+			void main ()
+			{
+				${SETUP}
+				out0 = func(float(g = in0), modG(2), --g > 0, g);
+				${OUTPUT}
+			}
+		""
+	end
+
+end # misc
diff --git a/external/vulkancts/data/vulkan/glsl/es310/linkage.test b/external/vulkancts/data/vulkan/glsl/es310/linkage.test
new file mode 100644
index 0000000..d0cec0f
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/linkage.test
@@ -0,0 +1,1885 @@
+
+# Varying tests
+group varying "Varying linkage"
+
+	# Linking rules
+	group rules "Varying linking rules"
+		# not declared in vertex shader, declared in fragment shader
+		case fragment_declare
+			version 310 es
+			desc "varying declared in fragment shader, no reference in vertex shader"
+			values { output float out0 = 1.0; }
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				void main()
+				{
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				in mediump float var;
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					out0 = 1.0;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		# declared in vertex shader, no reference in frag shader
+		case vertex_declare
+			version 310 es
+			desc "varying declared in vertex shader, no reference in fragment shader"
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# declared in vertex shader, declared in frag shader
+		case both_declare
+			version 310 es
+			desc "varying declared in both vertex and fragment shader, but not used"
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				in mediump float var;
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# declared in vertex shader, static use in frag shader
+		case vertex_declare_fragment_use
+			version 310 es
+			desc "varying declared in both shaders, statically used in fragment shader"
+			values { uniform bool u_false = false; }
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				in mediump float var;
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					if (u_false)
+						${FRAG_COLOR} = vec4(var);
+					else
+						${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# static use in vertex shader, no reference in fragment shader
+		case vertex_use_fragment_declare
+			version 310 es
+			desc "varying declared and statically used in vertex shader, no reference in fragment shader"
+			values { uniform bool u_false = false; }
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					if (u_false)
+						var = 1.0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# static use in vertex shader, declared in fragment shader
+		case vertex_use_declare_fragment
+			version 310 es
+			desc "varying declared and statically used in vertex shader, only declared in fragment shader"
+			values { uniform bool u_false = false; }
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					if (u_false)
+						var = 1.0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				in mediump float var;
+				${FRAGMENT_DECLARATIONS}
+				void main()
+				{
+					${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# static use in vertex shader, used in fragment shader
+		case vertex_use_fragment_use
+			version 310 es
+			desc "varying statically used in both vertex and fragment shader"
+			values { uniform bool u_false = false; }
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					if (u_false)
+						var = 1.0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				in mediump float var;
+				void main()
+				{
+					if (u_false)
+						${FRAG_COLOR} = vec4(var);
+					else
+						${FRAG_COLOR} = vec4(1.0);
+				}
+			""
+		end
+
+		# differing precision tests
+		case differing_precision_1
+			version 310 es
+			desc "varying declared as highp in vertex shader, but mediump in fragment shader"
+			values
+			{
+				input float in0		= [ -1.25 | -25.55 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.55 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out highp float var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mediump float var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		# differing precision tests
+		case differing_precision_2
+			version 310 es
+			desc "varying declared as highp in vertex shader, but lowp in fragment shader"
+			values
+			{
+				input float in0		= [ -1.25 | -25.56 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.56 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out highp vec2 var;
+				void main()
+				{
+					var = vec2(in0, 2.0*in0);
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in lowp vec2 var;
+				void main()
+				{
+					out0 = var.y - var.x;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		# differing precision tests
+		case differing_precision_3
+			version 310 es
+			desc "varying declared as lowp in vertex shader, but mediump in fragment shader"
+			values
+			{
+				input float in0		= [ -1.25 | -25.0 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.0 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out lowp vec4 var;
+				void main()
+				{
+					var = vec4(in0, 2.0*in0, -in0, -in0);
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mediump vec4 var;
+				void main()
+				{
+					out0 = var.x + var.y + var.z + var.w;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		# different interpolation
+		case differing_interpolation_2
+			version 310 es
+			desc "varying interpolation different (smooth vs. centroid)"
+			values
+			{
+				input float in0		= [ -1.25 | -25.0 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.0 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				smooth out mediump float var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				centroid in mediump float var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+	end
+
+	group basic_types "Basic varying types"
+		case float
+			version 310 es
+			desc "varying of type float"
+			values
+			{
+				input float in0		= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump float var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in float var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec2
+			version 310 es
+			desc "varying of type vec2"
+			values
+			{
+				input vec2 in0		= [ vec2(-1.25, 1.25) | vec2(-25.65, -7.25) | vec2(0.0, 1.0) | vec2(2.25, 2.25) | vec2(3.4, 9.5) | vec2(16.0, 32.0) ];
+				output vec2 out0	= [ vec2(-1.25, 1.25) | vec2(-25.65, -7.25) | vec2(0.0, 1.0) | vec2(2.25, 2.25) | vec2(3.4, 9.5) | vec2(16.0, 32.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump vec2 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in vec2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec3
+			version 310 es
+			desc "varying of type vec3"
+			values
+			{
+				input vec3 in0		= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+				output vec3 out0	= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump vec3 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in vec3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec4
+			version 310 es
+			desc "varying of type vec4"
+			values
+			{
+				input vec4 in0		= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+				output vec4 out0	= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump vec4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in vec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2
+			version 310 es
+			desc "varying of type mat2"
+			values
+			{
+				input mat2 in0		= [ mat2(1.0, 1.0, 1.0, 1.0) | mat2(-1.25, 1.25, -9.5, -12.2) | mat2(-25.65, -7.25, 14.21, -77.7) | mat2(0.0, 1.0, -1.0, 2.0) | mat2(2.25, 2.25, 22.5, 225.0) | mat2(3.4, 9.5, 19.5, 29.5) | mat2(16.0, 32.0, -64.0, -128.0) ];
+				output mat2 out0	= [ mat2(1.0, 1.0, 1.0, 1.0) | mat2(-1.25, 1.25, -9.5, -12.2) | mat2(-25.65, -7.25, 14.21, -77.7) | mat2(0.0, 1.0, -1.0, 2.0) | mat2(2.25, 2.25, 22.5, 225.0) | mat2(3.4, 9.5, 19.5, 29.5) | mat2(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat2 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2x3
+			version 310 es
+			desc "varying of type mat2x3"
+			values
+			{
+				input mat2x3 in0	= [ mat2x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+				output mat2x3 out0	= [ mat2x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat2x3 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat2x3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2x4
+			version 310 es
+			desc "varying of type mat2x4"
+			values
+			{
+				input mat2x4 in0	= [ mat2x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+				output mat2x4 out0	= [ mat2x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat2x4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat2x4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3x2
+			version 310 es
+			desc "varying of type mat3x2"
+			values
+			{
+				input mat3x2 in0	= [ mat3x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+				output mat3x2 out0	= [ mat3x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat3x2 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat3x2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3
+			version 310 es
+			desc "varying of type mat3"
+			values
+			{
+				input mat3 in0		= [ mat3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 9.9) | mat3(0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0, -9.9) | mat3(3.4, 9.5, 19.5, 29.5, 16.0, 32.0, -64.0, -128.0, 256.0) ];
+				output mat3 out0	= [ mat3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 9.9) | mat3(0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0, -9.9) | mat3(3.4, 9.5, 19.5, 29.5, 16.0, 32.0, -64.0, -128.0, 256.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat3 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3x4
+			version 310 es
+			desc "varying of type mat3x4"
+			values
+			{
+				input mat3x4 in0	= [ mat3x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+				output mat3x4 out0	= [ mat3x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat3x4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat3x4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4x2
+			version 310 es
+			desc "varying of type mat4x2"
+			values
+			{
+				input mat4x2 in0	= [ mat4x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+				output mat4x2 out0	= [ mat4x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat4x2 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat4x2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4x3
+			version 310 es
+			desc "varying of type mat4x3"
+			values
+			{
+				input mat4x3 in0	= [ mat4x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+				output mat4x3 out0	= [ mat4x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat4x3 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat4x3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4
+			version 310 es
+			desc "varying of type mat4"
+			values
+			{
+				input mat4 in0		= [ mat4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0) ];
+				output mat4 out0	= [ mat4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				out mediump mat4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in mat4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case int
+			version 310 es
+			desc "varying of type int"
+			values
+			{
+				input int in0		= [ -1 | -25 | 1 | 2 | 3 | 16 ];
+				output int out0		= [ -1 | -25 | 1 | 2 | 3 | 16 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump int var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in int var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec2
+			version 310 es
+			desc "varying of type ivec2"
+			values
+			{
+				input ivec2 in0		= [ ivec2(-1, 1) | ivec2(-25, 25) | ivec2(1, 1) | ivec2(2, 3) | ivec2(16, 17) ];
+				output ivec2 out0	= [ ivec2(-1, 1) | ivec2(-25, 25) | ivec2(1, 1) | ivec2(2, 3) | ivec2(16, 17) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump ivec2 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in ivec2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec3
+			version 310 es
+			desc "varying of type ivec3"
+			values
+			{
+				input ivec3 in0		= [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
+				output ivec3 out0	= [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump ivec3 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in ivec3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec4
+			version 310 es
+			desc "varying of type ivec4"
+			values
+			{
+				input ivec4 in0		= [ ivec4(-1, 1, -2, 2) | ivec4(-25, 25, -3, 3) | ivec4(1, 1, 1, 1) | ivec4(2, 3, 4, 5) | ivec4(16, 17, 18, 19) ];
+				output ivec4 out0	= [ ivec4(-1, 1, -2, 2) | ivec4(-25, 25, -3, 3) | ivec4(1, 1, 1, 1) | ivec4(2, 3, 4, 5) | ivec4(16, 17, 18, 19) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump ivec4 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in ivec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uint
+			version 310 es
+			desc "varying of type int"
+			values
+			{
+				input uint in0			= [ 1 | 2 | 3 | 16 ];
+				output uint out0		= [ 1 | 2 | 3 | 16 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump uint var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in uint var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec2
+			version 310 es
+			desc "varying of type uvec2"
+			values
+			{
+				input uvec2 in0		= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) ];
+				output uvec2 out0	= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump uvec2 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in uvec2 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec3
+			version 310 es
+			desc "varying of type uvec3"
+			values
+			{
+				input uvec3 in0		= [ uvec3(1, 1, 2) | uvec3(25, 25, 3) | uvec3(1, 1, 1) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
+				output uvec3 out0	= [ uvec3(1, 1, 2) | uvec3(25, 25, 3) | uvec3(1, 1, 1) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump uvec3 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in uvec3 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec4
+			version 310 es
+			desc "varying of type uvec4"
+			values
+			{
+				input uvec4 in0		= [ uvec4(1, 1, 2, 2) | uvec4(25, 25, 3, 3) | uvec4(1, 1, 1, 1) | uvec4(2, 3, 4, 5) | uvec4(16, 17, 18, 19) ];
+				output uvec4 out0	= [ uvec4(1, 1, 2, 2) | uvec4(25, 25, 3, 3) | uvec4(1, 1, 1, 1) | uvec4(2, 3, 4, 5) | uvec4(16, 17, 18, 19) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump uvec4 var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				flat in uvec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+	end
+
+	group struct "Structure varyings"
+		case float
+			version 310 es
+			desc "varying of type float inside struct"
+			values
+			{
+				input float in0		= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump float a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump float a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec2
+			version 310 es
+			desc "varying of type vec2 inside struct"
+			values
+			{
+				input vec2 in0		= [ vec2(-1.25, 1.25) | vec2(-25.65, -7.25) | vec2(0.0, 1.0) | vec2(2.25, 2.25) | vec2(3.4, 9.5) | vec2(16.0, 32.0) ];
+				output vec2 out0	= [ vec2(-1.25, 1.25) | vec2(-25.65, -7.25) | vec2(0.0, 1.0) | vec2(2.25, 2.25) | vec2(3.4, 9.5) | vec2(16.0, 32.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump vec2 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump vec2 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec3
+			version 310 es
+			desc "varying of type vec3 inside struct"
+			values
+			{
+				input vec3 in0		= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+				output vec3 out0	= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump vec3 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump vec3 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case vec4
+			version 310 es
+			desc "varying of type vec4 inside struct"
+			values
+			{
+				input vec4 in0		= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+				output vec4 out0	= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump vec4 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump vec4 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2
+			version 310 es
+			desc "varying of type mat2 inside struct"
+			values
+			{
+				input mat2 in0		= [ mat2(1.0, 1.0, 1.0, 1.0) | mat2(-1.25, 1.25, -9.5, -12.2) | mat2(-25.65, -7.25, 14.21, -77.7) | mat2(0.0, 1.0, -1.0, 2.0) | mat2(2.25, 2.25, 22.5, 225.0) | mat2(3.4, 9.5, 19.5, 29.5) | mat2(16.0, 32.0, -64.0, -128.0) ];
+				output mat2 out0	= [ mat2(1.0, 1.0, 1.0, 1.0) | mat2(-1.25, 1.25, -9.5, -12.2) | mat2(-25.65, -7.25, 14.21, -77.7) | mat2(0.0, 1.0, -1.0, 2.0) | mat2(2.25, 2.25, 22.5, 225.0) | mat2(3.4, 9.5, 19.5, 29.5) | mat2(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat2 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat2 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2x3
+			version 310 es
+			desc "varying of type mat2x3 inside struct"
+			values
+			{
+				input mat2x3 in0	= [ mat2x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+				output mat2x3 out0	= [ mat2x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat2x3 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat2x3 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat2x4
+			version 310 es
+			desc "varying of type mat2x4 inside struct"
+			values
+			{
+				input mat2x4 in0	= [ mat2x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+				output mat2x4 out0	= [ mat2x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat2x4 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat2x4 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3x2
+			version 310 es
+			desc "varying of type mat3x2 inside struct"
+			values
+			{
+				input mat3x2 in0	= [ mat3x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+				output mat3x2 out0	= [ mat3x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat3x2 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat3x2 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3
+			version 310 es
+			desc "varying of type mat3 inside struct"
+			values
+			{
+				input mat3 in0		= [ mat3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 9.9) | mat3(0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0, -9.9) | mat3(3.4, 9.5, 19.5, 29.5, 16.0, 32.0, -64.0, -128.0, 256.0) ];
+				output mat3 out0	= [ mat3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 9.9) | mat3(0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0, -9.9) | mat3(3.4, 9.5, 19.5, 29.5, 16.0, 32.0, -64.0, -128.0, 256.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat3 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat3 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat3x4
+			version 310 es
+			desc "varying of type mat3x4 inside struct"
+			values
+			{
+				input mat3x4 in0	= [ mat3x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+				output mat3x4 out0	= [ mat3x4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat3x4 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat3x4 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4x2
+			version 310 es
+			desc "varying of type mat4x2 inside struct"
+			values
+			{
+				input mat4x2 in0	= [ mat4x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+				output mat4x2 out0	= [ mat4x2(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat4x2 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat4x2 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4x3
+			version 310 es
+			desc "varying of type mat4x3 inside struct"
+			values
+			{
+				input mat4x3 in0	= [ mat4x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+				output mat4x3 out0	= [ mat4x3(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat4x3 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat4x3 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case mat4
+			version 310 es
+			desc "varying of type mat4 inside struct"
+			values
+			{
+				input mat4 in0		= [ mat4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0) ];
+				output mat4 out0	= [ mat4(-1.25, 1.25, -9.5, -12.2, -25.65, -7.25, 14.21, -77.7, 0.0, 1.0, -1.0, 2.0, 2.25, 2.25, 22.5, 225.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump mat4 a; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump mat4 a; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case int
+			version 310 es
+			desc "varying of type int inside struct"
+			values
+			{
+				input int in0		= [ -1 | -25 | 1 | 2 | 3 | 16 ];
+				output int out0		= [ -1 | -25 | 1 | 2 | 3 | 16 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump int a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump int a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec2
+			version 310 es
+			desc "varying of type ivec2 inside struct"
+			values
+			{
+				input ivec2 in0		= [ ivec2(-1, 1) | ivec2(-25, 25) | ivec2(1, 1) | ivec2(2, 3) | ivec2(16, 17) ];
+				output ivec2 out0	= [ ivec2(-1, 1) | ivec2(-25, 25) | ivec2(1, 1) | ivec2(2, 3) | ivec2(16, 17) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump ivec2 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump ivec2 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec3
+			version 310 es
+			desc "varying of type ivec3 inside struct"
+			values
+			{
+				input ivec3 in0		= [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
+				output ivec3 out0	= [ ivec3(-1, 1, -2) | ivec3(-25, 25, -3) | ivec3(1, 1, 1) | ivec3(2, 3, 4) | ivec3(16, 17, 18) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump ivec3 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump ivec3 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case ivec4
+			version 310 es
+			desc "varying of type ivec4 inside struct"
+			values
+			{
+				input ivec4 in0		= [ ivec4(-1, 1, -2, 2) | ivec4(-25, 25, -3, 3) | ivec4(1, 1, 1, 1) | ivec4(2, 3, 4, 5) | ivec4(16, 17, 18, 19) ];
+				output ivec4 out0	= [ ivec4(-1, 1, -2, 2) | ivec4(-25, 25, -3, 3) | ivec4(1, 1, 1, 1) | ivec4(2, 3, 4, 5) | ivec4(16, 17, 18, 19) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump ivec4 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump ivec4 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uint
+			version 310 es
+			desc "varying of type uint in struct"
+			values
+			{
+				input uint in0			= [ 1 | 2 | 3 | 16 ];
+				output uint out0		= [ 1 | 2 | 3 | 16 ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump uint a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump uint a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec2
+			version 310 es
+			desc "varying of type uvec2 inside struct"
+			values
+			{
+				input uvec2 in0		= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) ];
+				output uvec2 out0	= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump uvec2 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump uvec2 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec3
+			version 310 es
+			desc "varying of type uvec3 inside struct"
+			values
+			{
+				input uvec3 in0		= [ uvec3(1, 1, 2) | uvec3(25, 25, 3) | uvec3(1, 1, 1) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
+				output uvec3 out0	= [ uvec3(1, 1, 2) | uvec3(25, 25, 3) | uvec3(1, 1, 1) | uvec3(2, 3, 4) | uvec3(16, 17, 18) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump uvec3 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump uvec3 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case uvec4
+			version 310 es
+			desc "varying of type uvec4 inside struct"
+			values
+			{
+				input uvec4 in0		= [ uvec4(1, 1, 2, 2) | uvec4(25, 25, 3, 3) | uvec4(1, 1, 1, 1) | uvec4(2, 3, 4, 5) | uvec4(16, 17, 18, 19) ];
+				output uvec4 out0	= [ uvec4(1, 1, 2, 2) | uvec4(25, 25, 3, 3) | uvec4(1, 1, 1, 1) | uvec4(2, 3, 4, 5) | uvec4(16, 17, 18, 19) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump uvec4 a; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump uvec4 a; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case float_vec3
+			version 310 es
+			desc "varyings of type float and vec3 inside struct"
+			values
+			{
+				input float in0		= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				input vec3 in1		= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+				output vec3 out1	= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump float a; highp vec3 b; };
+				out S var;
+				void main()
+				{
+					var.a = in0;
+					var.b = in1;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump float a; highp vec3 b; };
+				in S var;
+				void main()
+				{
+					out0 = var.a;
+					out1 = var.b;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case float_uvec2_vec3
+			version 310 es
+			desc "varyings of type float and vec3 inside struct"
+			values
+			{
+				input float in0		= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				output float out0	= [ -1.25 | -25.65 | 1.0 | 2.25 | 3.4 | 16.0 ];
+				input uvec2 in1		= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(8, 7) ];
+				output uvec2 out1	= [ uvec2(1, 1) | uvec2(25, 25) | uvec2(1, 1) | uvec2(2, 3) | uvec2(16, 17) | uvec2(8, 7) ];
+				input vec3 in2		= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+				output vec3 out2	= [ vec3(-1.25, 1.25, -9.5) | vec3(-25.65, -7.25, 14.21) | vec3(0.0, 1.0, -1.0) | vec3(2.25, 2.25, 22.5) | vec3(3.4, 9.5, 19.5) | vec3(16.0, 32.0, -64.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				struct S { mediump float a; highp uvec2 b; highp vec3 c; };
+				flat out S var;
+				void main()
+				{
+					${VERTEX_SETUP}
+					var.a = in0;
+					var.b = in1;
+					var.c = in2;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				struct S { mediump float a; highp uvec2 b; highp vec3 c; };
+				flat in S var;
+				void main()
+				{
+					out0 = var.a;
+					out1 = var.b;
+					out2 = var.c;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+	end
+
+	group interpolation "Varying interpolation modes"
+		case smooth
+			version 310 es
+			desc "varying of type vec4"
+			values
+			{
+				input vec4 in0		= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+				output vec4 out0	= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				smooth out mediump vec4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				smooth in vec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case centroid
+			version 310 es
+			desc "varying of type vec4"
+			values
+			{
+				input vec4 in0		= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+				output vec4 out0	= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				centroid out mediump vec4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				centroid in vec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+
+		case flat
+			version 310 es
+			desc "varying of type vec4"
+			values
+			{
+				input vec4 in0		= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+				output vec4 out0	= [ vec4(-1.25, 1.25, -9.5, -12.2) | vec4(-25.65, -7.25, 14.21, -77.7) | vec4(0.0, 1.0, -1.0, 2.0) | vec4(2.25, 2.25, 22.5, 225.0) | vec4(3.4, 9.5, 19.5, 29.5) | vec4(16.0, 32.0, -64.0, -128.0) ];
+			}
+			vertex ""
+				#version 310 es
+				${VERTEX_DECLARATIONS}
+				flat out mediump vec4 var;
+				void main()
+				{
+					var = in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				flat in vec4 var;
+				void main()
+				{
+					out0 = var;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+	end
+
+	group usage "Varying usage in shaders"
+		case readback_1
+			version 310 es
+			desc "read back (an already written) varying in the vertex shader"
+			values
+			{
+				input float in0		= [ 1.0 | 0.0 | -2.0 | 10.0 ];
+				output float out0	= [ 3.0 | 0.0 | -6.0 | 30.0 ];
+			}
+			vertex ""
+				#version 310 es
+				precision mediump float;
+				${VERTEX_DECLARATIONS}
+				out float var1;
+				out float var2;
+
+				void main()
+				{
+					var1 = in0;
+					var2 = var1 + in0;
+					${VERTEX_OUTPUT}
+				}
+			""
+			fragment ""
+				#version 310 es
+				precision mediump float;
+				${FRAGMENT_DECLARATIONS}
+				in float var1;
+				in float var2;
+
+				void main()
+				{
+					out0 = var1 + var2;
+					${FRAGMENT_OUTPUT}
+				}
+			""
+		end
+	end
+end
diff --git a/external/vulkancts/data/vulkan/glsl/es310/scoping.test b/external/vulkancts/data/vulkan/glsl/es310/scoping.test
new file mode 100644
index 0000000..9fc18a1
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/scoping.test
@@ -0,0 +1,443 @@
+group valid "Valid scoping and name redeclaration cases"
+
+	case local_variable_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = -1;
+
+			void main()
+			{
+				${SETUP}
+				int a = in0;
+
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case block_variable_hides_local_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				${SETUP}
+				int a = in0;
+				{
+					int a = -1;
+				}
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case block_variable_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = -1;
+
+			void main()
+			{
+				${SETUP}
+				{
+					int a = in0;
+
+					out0 = a;
+				}
+				${OUTPUT}
+			}
+		""
+	end
+
+	case for_init_statement_variable_hides_local_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				${SETUP}
+				int a = in0;
+				for (int a = 0; a < 10; a++)
+				{
+				}
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case while_condition_variable_hides_local_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				${SETUP}
+				int a = in0;
+				int i = 0;
+				while (bool a = (i < 1))
+				{
+					i++;
+				}
+				out0 = a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case for_init_statement_variable_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = 5;
+
+			void main()
+			{
+				${SETUP}
+				for (int a = 0; a < 10; a++)
+				{
+				}
+				out0 = in0 + a - 5;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case while_condition_variable_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = 5;
+
+			void main()
+			{
+				${SETUP}
+				int i = 0;
+				while (bool a = (i < 1))
+				{
+					i++;
+				}
+				out0 = in0 + a - 5;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case variable_in_if_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = 1;
+
+			void main()
+			{
+				${SETUP}
+				if (true)
+					int a = 42;
+				out0 = a*in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case variable_from_outer_scope_visible_in_initializer
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			void main()
+			{
+				${SETUP}
+				int a = in0;
+				{
+					int a = a+5, b = a-5;
+					out0 = b;
+					a = 42;
+				}
+				out0 = out0 + a - in0;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case local_int_variable_hides_struct_type
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct S { int val; };
+
+			void main()
+			{
+				${SETUP}
+				int S = S(in0).val;
+				out0 = S;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case local_struct_variable_hides_struct_type
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct S { int val; };
+
+			void main()
+			{
+				${SETUP}
+				S S = S(in0);
+				out0 = S.val;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case local_variable_hides_function
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int foo (int x) { return x; }
+
+			void main()
+			{
+				${SETUP}
+				int foo = in0;
+				out0 = foo;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case function_parameter_hides_global_variable
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int a = -1;
+
+			int func (int a) { return a; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case function_parameter_hides_struct_type
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			struct S { int x; };
+
+			int func (int S) { return S; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case function_parameter_hides_function
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int func (int func) { return func; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case local_variable_in_inner_scope_hides_function_parameter
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+			int func (int inp, int x) { { int x = 5; return inp + x - 5; } }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0, 42);
+				${OUTPUT}
+			}
+		""
+	end
+
+	case redeclare_function
+		version 310 es
+		values
+		{
+			input int in0 = [ 1 | 2 | 3 ];
+			output int out0 = [ 1 | 2 | 3 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+			${DECLARATIONS}
+
+			int func (int x);
+			int func (int);
+			int func (int inp) { return inp; }
+
+			void main()
+			{
+				${SETUP}
+				out0 = func(in0);
+				${OUTPUT}
+			}
+		""
+	end
+
+end
diff --git a/external/vulkancts/data/vulkan/glsl/es310/swizzles.test b/external/vulkancts/data/vulkan/glsl/es310/swizzles.test
new file mode 100644
index 0000000..5a853a6
--- /dev/null
+++ b/external/vulkancts/data/vulkan/glsl/es310/swizzles.test
@@ -0,0 +1,7459 @@
+# WARNING: This file is auto-generated. Do NOT modify it manually, but rather
+# modify the generating script file. Otherwise changes will be lost!
+
+group vector_swizzles "Vector Swizzles"
+
+	case mediump_vec2_x
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_xx
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(-0.5, -0.5) | vec2(-32.0, -32.0) | vec2(-0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_xy
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_yx
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.5, 0.0) | vec2(1.25, 1.0) | vec2(-2.25, -0.5) | vec2(64.0, -32.0) | vec2(-0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_yxy
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_xyxx
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_yyyy
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_s
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_ss
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(-0.5, -0.5) | vec2(-32.0, -32.0) | vec2(-0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_st
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.st;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_ts
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.5, 0.0) | vec2(1.25, 1.0) | vec2(-2.25, -0.5) | vec2(64.0, -32.0) | vec2(-0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_tst
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_stss
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_tttt
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_r
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_rr
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.0) | vec2(1.0, 1.0) | vec2(-0.5, -0.5) | vec2(-32.0, -32.0) | vec2(-0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_rg
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_gr
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec2 out0 = [ vec2(0.5, 0.0) | vec2(1.25, 1.0) | vec2(-2.25, -0.5) | vec2(64.0, -32.0) | vec2(-0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_grg
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_rgrr
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec2_gggg
+		version 310 es
+		values
+		{
+			input vec2 in0 = [ vec2(0.0, 0.5) | vec2(1.0, 1.25) | vec2(-0.5, -2.25) | vec2(-32.0, 64.0) | vec2(-0.75, -0.0322580645161) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_x
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_z
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.75 | 1.125 | -4.875 | -51.0 | 0.0526315789474 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.z;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_xz
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.0, 0.75) | vec2(1.0, 1.125) | vec2(-0.5, -4.875) | vec2(-32.0, -51.0) | vec2(-0.75, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_zz
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.75, 0.75) | vec2(1.125, 1.125) | vec2(-4.875, -4.875) | vec2(-51.0, -51.0) | vec2(0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_xyz
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_zyx
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.5, 0.0) | vec3(1.125, 1.25, 1.0) | vec3(-4.875, -2.25, -0.5) | vec3(-51.0, 64.0, -32.0) | vec3(0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_xxx
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(-0.5, -0.5, -0.5) | vec3(-32.0, -32.0, -32.0) | vec3(-0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_zzz
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.75) | vec3(1.125, 1.125, 1.125) | vec3(-4.875, -4.875, -4.875) | vec3(-51.0, -51.0, -51.0) | vec3(0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_zzy
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.5) | vec3(1.125, 1.125, 1.25) | vec3(-4.875, -4.875, -2.25) | vec3(-51.0, -51.0, 64.0) | vec3(0.0526315789474, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_yxy
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_xzx
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.75, 0.0) | vec3(1.0, 1.125, 1.0) | vec3(-0.5, -4.875, -0.5) | vec3(-32.0, -51.0, -32.0) | vec3(-0.75, 0.0526315789474, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xzx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_xyyx
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.5, 0.0) | vec4(1.0, 1.25, 1.25, 1.0) | vec4(-0.5, -2.25, -2.25, -0.5) | vec4(-32.0, 64.0, 64.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_zzzz
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.75, 0.75) | vec4(1.125, 1.125, 1.125, 1.125) | vec4(-4.875, -4.875, -4.875, -4.875) | vec4(-51.0, -51.0, -51.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_s
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_p
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.75 | 1.125 | -4.875 | -51.0 | 0.0526315789474 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.p;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_sp
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.0, 0.75) | vec2(1.0, 1.125) | vec2(-0.5, -4.875) | vec2(-32.0, -51.0) | vec2(-0.75, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_pp
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.75, 0.75) | vec2(1.125, 1.125) | vec2(-4.875, -4.875) | vec2(-51.0, -51.0) | vec2(0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_stp
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_pts
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.5, 0.0) | vec3(1.125, 1.25, 1.0) | vec3(-4.875, -2.25, -0.5) | vec3(-51.0, 64.0, -32.0) | vec3(0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_sss
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(-0.5, -0.5, -0.5) | vec3(-32.0, -32.0, -32.0) | vec3(-0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_ppp
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.75) | vec3(1.125, 1.125, 1.125) | vec3(-4.875, -4.875, -4.875) | vec3(-51.0, -51.0, -51.0) | vec3(0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_ppt
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.5) | vec3(1.125, 1.125, 1.25) | vec3(-4.875, -4.875, -2.25) | vec3(-51.0, -51.0, 64.0) | vec3(0.0526315789474, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_tst
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_sps
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.75, 0.0) | vec3(1.0, 1.125, 1.0) | vec3(-0.5, -4.875, -0.5) | vec3(-32.0, -51.0, -32.0) | vec3(-0.75, 0.0526315789474, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sps;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_stts
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.5, 0.0) | vec4(1.0, 1.25, 1.25, 1.0) | vec4(-0.5, -2.25, -2.25, -0.5) | vec4(-32.0, 64.0, 64.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_pppp
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.75, 0.75) | vec4(1.125, 1.125, 1.125, 1.125) | vec4(-4.875, -4.875, -4.875, -4.875) | vec4(-51.0, -51.0, -51.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_r
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_b
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output float out0 = [ 0.75 | 1.125 | -4.875 | -51.0 | 0.0526315789474 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.b;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_rb
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.0, 0.75) | vec2(1.0, 1.125) | vec2(-0.5, -4.875) | vec2(-32.0, -51.0) | vec2(-0.75, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_bb
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec2 out0 = [ vec2(0.75, 0.75) | vec2(1.125, 1.125) | vec2(-4.875, -4.875) | vec2(-51.0, -51.0) | vec2(0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_rgb
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_bgr
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.5, 0.0) | vec3(1.125, 1.25, 1.0) | vec3(-4.875, -2.25, -0.5) | vec3(-51.0, 64.0, -32.0) | vec3(0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_rrr
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.0, 0.0) | vec3(1.0, 1.0, 1.0) | vec3(-0.5, -0.5, -0.5) | vec3(-32.0, -32.0, -32.0) | vec3(-0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_bbb
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.75) | vec3(1.125, 1.125, 1.125) | vec3(-4.875, -4.875, -4.875) | vec3(-51.0, -51.0, -51.0) | vec3(0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_bbg
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.75, 0.75, 0.5) | vec3(1.125, 1.125, 1.25) | vec3(-4.875, -4.875, -2.25) | vec3(-51.0, -51.0, 64.0) | vec3(0.0526315789474, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_grg
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.5, 0.0, 0.5) | vec3(1.25, 1.0, 1.25) | vec3(-2.25, -0.5, -2.25) | vec3(64.0, -32.0, 64.0) | vec3(-0.0322580645161, -0.75, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_rbr
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec3 out0 = [ vec3(0.0, 0.75, 0.0) | vec3(1.0, 1.125, 1.0) | vec3(-0.5, -4.875, -0.5) | vec3(-32.0, -51.0, -32.0) | vec3(-0.75, 0.0526315789474, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rbr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_rggr
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.5, 0.0) | vec4(1.0, 1.25, 1.25, 1.0) | vec4(-0.5, -2.25, -2.25, -0.5) | vec4(-32.0, 64.0, 64.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rggr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec3_bbbb
+		version 310 es
+		values
+		{
+			input vec3 in0 = [ vec3(0.0, 0.5, 0.75) | vec3(1.0, 1.25, 1.125) | vec3(-0.5, -2.25, -4.875) | vec3(-32.0, 64.0, -51.0) | vec3(-0.75, -0.0322580645161, 0.0526315789474) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.75, 0.75) | vec4(1.125, 1.125, 1.125, 1.125) | vec4(-4.875, -4.875, -4.875, -4.875) | vec4(-51.0, -51.0, -51.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.0526315789474, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_x
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_w
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.825 | 1.75 | 9.0 | 24.0 | 0.25 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.w;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wx
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.0) | vec2(1.75, 1.0) | vec2(9.0, -0.5) | vec2(24.0, -32.0) | vec2(0.25, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wz
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.75) | vec2(1.75, 1.125) | vec2(9.0, -4.875) | vec2(24.0, -51.0) | vec2(0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_www
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.825, 0.825) | vec3(1.75, 1.75, 1.75) | vec3(9.0, 9.0, 9.0) | vec3(24.0, 24.0, 24.0) | vec3(0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.www;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_yyw
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.5, 0.5, 0.825) | vec3(1.25, 1.25, 1.75) | vec3(-2.25, -2.25, 9.0) | vec3(64.0, 64.0, 24.0) | vec3(-0.0322580645161, -0.0322580645161, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wzy
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.75, 0.5) | vec3(1.75, 1.125, 1.25) | vec3(9.0, -4.875, -2.25) | vec3(24.0, -51.0, 64.0) | vec3(0.25, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_xyzw
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wzyx
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.5, 0.0) | vec4(1.75, 1.125, 1.25, 1.0) | vec4(9.0, -4.875, -2.25, -0.5) | vec4(24.0, -51.0, 64.0, -32.0) | vec4(0.25, 0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_xxxx
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(-0.5, -0.5, -0.5, -0.5) | vec4(-32.0, -32.0, -32.0, -32.0) | vec4(-0.75, -0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_yyyy
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wwww
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.825) | vec4(1.75, 1.75, 1.75, 1.75) | vec4(9.0, 9.0, 9.0, 9.0) | vec4(24.0, 24.0, 24.0, 24.0) | vec4(0.25, 0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwww;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wzzw
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.75, 0.825) | vec4(1.75, 1.125, 1.125, 1.75) | vec4(9.0, -4.875, -4.875, 9.0) | vec4(24.0, -51.0, -51.0, 24.0) | vec4(0.25, 0.0526315789474, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_wwwy
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.5) | vec4(1.75, 1.75, 1.75, 1.25) | vec4(9.0, 9.0, 9.0, -2.25) | vec4(24.0, 24.0, 24.0, 64.0) | vec4(0.25, 0.25, 0.25, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwwy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_xyxx
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_zzwz
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.825, 0.75) | vec4(1.125, 1.125, 1.75, 1.125) | vec4(-4.875, -4.875, 9.0, -4.875) | vec4(-51.0, -51.0, 24.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzwz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_s
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_q
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.825 | 1.75 | 9.0 | 24.0 | 0.25 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.q;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qs
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.0) | vec2(1.75, 1.0) | vec2(9.0, -0.5) | vec2(24.0, -32.0) | vec2(0.25, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qs;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qp
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.75) | vec2(1.75, 1.125) | vec2(9.0, -4.875) | vec2(24.0, -51.0) | vec2(0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qqq
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.825, 0.825) | vec3(1.75, 1.75, 1.75) | vec3(9.0, 9.0, 9.0) | vec3(24.0, 24.0, 24.0) | vec3(0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_ttq
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.5, 0.5, 0.825) | vec3(1.25, 1.25, 1.75) | vec3(-2.25, -2.25, 9.0) | vec3(64.0, 64.0, 24.0) | vec3(-0.0322580645161, -0.0322580645161, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ttq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qpt
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.75, 0.5) | vec3(1.75, 1.125, 1.25) | vec3(9.0, -4.875, -2.25) | vec3(24.0, -51.0, 64.0) | vec3(0.25, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_stpq
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stpq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qpts
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.5, 0.0) | vec4(1.75, 1.125, 1.25, 1.0) | vec4(9.0, -4.875, -2.25, -0.5) | vec4(24.0, -51.0, 64.0, -32.0) | vec4(0.25, 0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_ssss
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(-0.5, -0.5, -0.5, -0.5) | vec4(-32.0, -32.0, -32.0, -32.0) | vec4(-0.75, -0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ssss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_tttt
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qqqq
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.825) | vec4(1.75, 1.75, 1.75, 1.75) | vec4(9.0, 9.0, 9.0, 9.0) | vec4(24.0, 24.0, 24.0, 24.0) | vec4(0.25, 0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qppq
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.75, 0.825) | vec4(1.75, 1.125, 1.125, 1.75) | vec4(9.0, -4.875, -4.875, 9.0) | vec4(24.0, -51.0, -51.0, 24.0) | vec4(0.25, 0.0526315789474, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qppq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_qqqt
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.5) | vec4(1.75, 1.75, 1.75, 1.25) | vec4(9.0, 9.0, 9.0, -2.25) | vec4(24.0, 24.0, 24.0, 64.0) | vec4(0.25, 0.25, 0.25, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_stss
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_ppqp
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.825, 0.75) | vec4(1.125, 1.125, 1.75, 1.125) | vec4(-4.875, -4.875, 9.0, -4.875) | vec4(-51.0, -51.0, 24.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppqp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_r
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.0 | 1.0 | -0.5 | -32.0 | -0.75 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_a
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output float out0 = [ 0.825 | 1.75 | 9.0 | 24.0 | 0.25 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_ar
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.0) | vec2(1.75, 1.0) | vec2(9.0, -0.5) | vec2(24.0, -32.0) | vec2(0.25, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ar;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_ab
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec2 out0 = [ vec2(0.825, 0.75) | vec2(1.75, 1.125) | vec2(9.0, -4.875) | vec2(24.0, -51.0) | vec2(0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ab;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_aaa
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.825, 0.825) | vec3(1.75, 1.75, 1.75) | vec3(9.0, 9.0, 9.0) | vec3(24.0, 24.0, 24.0) | vec3(0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_gga
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.5, 0.5, 0.825) | vec3(1.25, 1.25, 1.75) | vec3(-2.25, -2.25, 9.0) | vec3(64.0, 64.0, 24.0) | vec3(-0.0322580645161, -0.0322580645161, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gga;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_abg
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec3 out0 = [ vec3(0.825, 0.75, 0.5) | vec3(1.75, 1.125, 1.25) | vec3(9.0, -4.875, -2.25) | vec3(24.0, -51.0, 64.0) | vec3(0.25, 0.0526315789474, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_rgba
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_abgr
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.5, 0.0) | vec4(1.75, 1.125, 1.25, 1.0) | vec4(9.0, -4.875, -2.25, -0.5) | vec4(24.0, -51.0, 64.0, -32.0) | vec4(0.25, 0.0526315789474, -0.0322580645161, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_rrrr
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.0, 0.0, 0.0) | vec4(1.0, 1.0, 1.0, 1.0) | vec4(-0.5, -0.5, -0.5, -0.5) | vec4(-32.0, -32.0, -32.0, -32.0) | vec4(-0.75, -0.75, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_gggg
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.5, 0.5, 0.5, 0.5) | vec4(1.25, 1.25, 1.25, 1.25) | vec4(-2.25, -2.25, -2.25, -2.25) | vec4(64.0, 64.0, 64.0, 64.0) | vec4(-0.0322580645161, -0.0322580645161, -0.0322580645161, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_aaaa
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.825) | vec4(1.75, 1.75, 1.75, 1.75) | vec4(9.0, 9.0, 9.0, 9.0) | vec4(24.0, 24.0, 24.0, 24.0) | vec4(0.25, 0.25, 0.25, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_abba
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.75, 0.75, 0.825) | vec4(1.75, 1.125, 1.125, 1.75) | vec4(9.0, -4.875, -4.875, 9.0) | vec4(24.0, -51.0, -51.0, 24.0) | vec4(0.25, 0.0526315789474, 0.0526315789474, 0.25) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_aaag
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.825, 0.825, 0.825, 0.5) | vec4(1.75, 1.75, 1.75, 1.25) | vec4(9.0, 9.0, 9.0, -2.25) | vec4(24.0, 24.0, 24.0, 64.0) | vec4(0.25, 0.25, 0.25, -0.0322580645161) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaag;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_rgrr
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.0, 0.5, 0.0, 0.0) | vec4(1.0, 1.25, 1.0, 1.0) | vec4(-0.5, -2.25, -0.5, -0.5) | vec4(-32.0, 64.0, -32.0, -32.0) | vec4(-0.75, -0.0322580645161, -0.75, -0.75) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_vec4_bbab
+		version 310 es
+		values
+		{
+			input vec4 in0 = [ vec4(0.0, 0.5, 0.75, 0.825) | vec4(1.0, 1.25, 1.125, 1.75) | vec4(-0.5, -2.25, -4.875, 9.0) | vec4(-32.0, 64.0, -51.0, 24.0) | vec4(-0.75, -0.0322580645161, 0.0526315789474, 0.25) ];
+			output vec4 out0 = [ vec4(0.75, 0.75, 0.825, 0.75) | vec4(1.125, 1.125, 1.75, 1.125) | vec4(-4.875, -4.875, 9.0, -4.875) | vec4(-51.0, -51.0, 24.0, -51.0) | vec4(0.0526315789474, 0.0526315789474, 0.25, 0.0526315789474) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbab;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_x
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_xx
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_xy
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_yx
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-2, 0) | ivec2(64, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_yxy
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_xyxx
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_yyyy
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_s
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_ss
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_st
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.st;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_ts
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-2, 0) | ivec2(64, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_tst
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_stss
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_tttt
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_r
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_rr
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, 0) | ivec2(-32, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_rg
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_gr
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-2, 0) | ivec2(64, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_grg
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_rgrr
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec2_gggg
+		version 310 es
+		values
+		{
+			input ivec2 in0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -2) | ivec2(-32, 64) | ivec2(0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_x
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_z
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | -4 | -51 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.z;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_xz
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -4) | ivec2(-32, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_zz
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-4, -4) | ivec2(-51, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_xyz
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_zyx
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -2, 0) | ivec3(-51, 64, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_xxx
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, -32, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_zzz
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -4) | ivec3(-51, -51, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_zzy
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -2) | ivec3(-51, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_yxy
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_xzx
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -4, 0) | ivec3(-32, -51, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xzx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_xyyx
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -2, 0) | ivec4(-32, 64, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_zzzz
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, -4, -4) | ivec4(-51, -51, -51, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_s
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_p
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | -4 | -51 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.p;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_sp
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -4) | ivec2(-32, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_pp
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-4, -4) | ivec2(-51, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_stp
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_pts
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -2, 0) | ivec3(-51, 64, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_sss
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, -32, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_ppp
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -4) | ivec3(-51, -51, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_ppt
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -2) | ivec3(-51, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_tst
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_sps
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -4, 0) | ivec3(-32, -51, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sps;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_stts
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -2, 0) | ivec4(-32, 64, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_pppp
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, -4, -4) | ivec4(-51, -51, -51, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_r
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_b
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output int out0 = [ 0 | 1 | -4 | -51 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.b;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_rb
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(0, -4) | ivec2(-32, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_bb
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(-4, -4) | ivec2(-51, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_rgb
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_bgr
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -2, 0) | ivec3(-51, 64, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_rrr
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, 0, 0) | ivec3(-32, -32, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_bbb
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -4) | ivec3(-51, -51, -51) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_bbg
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-4, -4, -2) | ivec3(-51, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_grg
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, 0, -2) | ivec3(64, -32, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_rbr
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -4, 0) | ivec3(-32, -51, -32) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rbr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_rggr
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -2, 0) | ivec4(-32, 64, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rggr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec3_bbbb
+		version 310 es
+		values
+		{
+			input ivec3 in0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(0, -2, -4) | ivec3(-32, 64, -51) | ivec3(0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, -4, -4) | ivec4(-51, -51, -51, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_x
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_w
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 9 | 24 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.w;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wx
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, 0) | ivec2(24, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wz
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, -4) | ivec2(24, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_www
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, 9, 9) | ivec3(24, 24, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.www;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_yyw
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, -2, 9) | ivec3(64, 64, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wzy
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, -4, -2) | ivec3(24, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_xyzw
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wzyx
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -2, 0) | ivec4(24, -51, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_xxxx
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, -32, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_yyyy
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wwww
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, 9) | ivec4(24, 24, 24, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwww;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wzzw
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -4, 9) | ivec4(24, -51, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_wwwy
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, -2) | ivec4(24, 24, 24, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwwy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_xyxx
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_zzwz
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, 9, -4) | ivec4(-51, -51, 24, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzwz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_s
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_q
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 9 | 24 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.q;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qs
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, 0) | ivec2(24, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qs;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qp
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, -4) | ivec2(24, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qqq
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, 9, 9) | ivec3(24, 24, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_ttq
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, -2, 9) | ivec3(64, 64, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ttq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qpt
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, -4, -2) | ivec3(24, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_stpq
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stpq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qpts
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -2, 0) | ivec4(24, -51, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_ssss
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, -32, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ssss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_tttt
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qqqq
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, 9) | ivec4(24, 24, 24, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qppq
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -4, 9) | ivec4(24, -51, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qppq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_qqqt
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, -2) | ivec4(24, 24, 24, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_stss
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_ppqp
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, 9, -4) | ivec4(-51, -51, 24, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppqp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_r
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 0 | -32 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_a
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output int out0 = [ 0 | 1 | 9 | 24 | 0 ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_ar
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, 0) | ivec2(24, -32) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ar;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_ab
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec2 out0 = [ ivec2(0, 0) | ivec2(1, 1) | ivec2(9, -4) | ivec2(24, -51) | ivec2(0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ab;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_aaa
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, 9, 9) | ivec3(24, 24, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_gga
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(-2, -2, 9) | ivec3(64, 64, 24) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gga;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_abg
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec3 out0 = [ ivec3(0, 0, 0) | ivec3(1, 1, 1) | ivec3(9, -4, -2) | ivec3(24, -51, 64) | ivec3(0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_rgba
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_abgr
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -2, 0) | ivec4(24, -51, 64, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_rrrr
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, 0, 0, 0) | ivec4(-32, -32, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_gggg
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-2, -2, -2, -2) | ivec4(64, 64, 64, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_aaaa
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, 9) | ivec4(24, 24, 24, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_abba
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, -4, -4, 9) | ivec4(24, -51, -51, 24) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_aaag
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(9, 9, 9, -2) | ivec4(24, 24, 24, 64) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaag;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_rgrr
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, 0, 0) | ivec4(-32, 64, -32, -32) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_ivec4_bbab
+		version 310 es
+		values
+		{
+			input ivec4 in0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(0, -2, -4, 9) | ivec4(-32, 64, -51, 24) | ivec4(0, 0, 0, 0) ];
+			output ivec4 out0 = [ ivec4(0, 0, 0, 0) | ivec4(1, 1, 1, 1) | ivec4(-4, -4, 9, -4) | ivec4(-51, -51, 24, -51) | ivec4(0, 0, 0, 0) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbab;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_x
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_xx
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_xy
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_yx
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_yxy
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_xyxx
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_yyyy
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_s
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_ss
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_st
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.st;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_ts
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_tst
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_stss
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_tttt
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_r
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_rr
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_rg
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_gr
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec2 out0 = [ bvec2(false, true) | bvec2(false, false) | bvec2(true, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_grg
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_rgrr
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec2_gggg
+		version 310 es
+		values
+		{
+			input bvec2 in0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, true) | bvec2(true, true) | bvec2(false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_x
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_z
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ false | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.z;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_xz
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_zz
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_xyz
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_zyx
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_xxx
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_zzz
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_zzy
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_yxy
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yxy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_xzx
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xzx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_xyyx
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(false, true, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_zzzz
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzzz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_s
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_p
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ false | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.p;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_sp
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_pp
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_stp
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_pts
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_sss
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_ppp
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_ppt
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_tst
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tst;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_sps
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.sps;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_stts
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(false, true, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_pppp
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.pppp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_r
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_b
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bool out0 = [ false | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.b;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_rb
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_bb
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec2 out0 = [ bvec2(false, false) | bvec2(false, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_rgb
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_bgr
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_rrr
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_bbb
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_bbg
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, false) | bvec3(false, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_grg
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, true, false) | bvec3(false, false, false) | bvec3(true, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.grg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_rbr
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, true) | bvec3(false, false, false) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rbr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_rggr
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(false, true, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rggr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec3_bbbb
+		version 310 es
+		values
+		{
+			input bvec3 in0 = [ bvec3(true, false, false) | bvec3(false, false, false) | bvec3(false, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbbb;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_x
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.x;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_w
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.w;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wx
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wz
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_www
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.www;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_yyw
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, true) | bvec3(true, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wzy
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(true, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_xyzw
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wzyx
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, false) | bvec4(false, false, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzyx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_xxxx
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xxxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_yyyy
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.yyyy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wwww
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwww;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wzzw
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wzzw;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_wwwy
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, false) | bvec4(true, true, true, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.wwwy;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_xyxx
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.xyxx;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_zzwz
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(false, false, true, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.zzwz;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_s
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.s;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_q
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.q;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qs
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qs;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qp
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qqq
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_ttq
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, true) | bvec3(true, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ttq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qpt
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(true, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_stpq
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stpq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qpts
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, false) | bvec4(false, false, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qpts;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_ssss
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ssss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_tttt
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.tttt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qqqq
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qppq
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qppq;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_qqqt
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, false) | bvec4(true, true, true, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.qqqt;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_stss
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.stss;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_ppqp
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(false, false, true, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ppqp;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_r
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | false | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.r;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_a
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bool out0 = [ true | true | false | true | false ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.a;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_ar
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, true) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ar;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_ab
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec2 out0 = [ bvec2(true, false) | bvec2(true, false) | bvec2(false, false) | bvec2(true, true) | bvec2(false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.ab;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_aaa
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, true, true) | bvec3(true, true, true) | bvec3(false, false, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_gga
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(false, false, true) | bvec3(false, false, true) | bvec3(true, true, false) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gga;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_abg
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec3 out0 = [ bvec3(true, false, false) | bvec3(true, false, false) | bvec3(false, false, true) | bvec3(true, true, true) | bvec3(false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_rgba
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_abgr
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, false) | bvec4(false, false, true, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abgr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_rrrr
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rrrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_gggg
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, false, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.gggg;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_aaaa
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaaa;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_abba
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, false, true) | bvec4(true, false, false, true) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.abba;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_aaag
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, true, true, false) | bvec4(true, true, true, false) | bvec4(false, false, false, true) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.aaag;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_rgrr
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(true, false, true, true) | bvec4(false, false, false, false) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.rgrr;
+				${OUTPUT}
+			}
+		""
+	end
+
+	case mediump_bvec4_bbab
+		version 310 es
+		values
+		{
+			input bvec4 in0 = [ bvec4(true, false, false, true) | bvec4(false, false, false, true) | bvec4(false, true, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+			output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(false, false, true, false) | bvec4(false, false, false, false) | bvec4(true, true, true, true) | bvec4(false, false, false, false) ];
+		}
+
+		both ""
+			#version 310 es
+			precision mediump float;
+
+			${DECLARATIONS}
+
+			void main()
+			{
+				${SETUP}
+				out0 = in0.bbab;
+				${OUTPUT}
+			}
+		""
+	end
+
+
+end # vector_swizzles
diff --git a/external/vulkancts/framework/vulkan/CMakeLists.txt b/external/vulkancts/framework/vulkan/CMakeLists.txt
new file mode 100644
index 0000000..ab67b01
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/CMakeLists.txt
@@ -0,0 +1,71 @@
+# vk - Vulkan utilites
+
+set(VKUTIL_SRCS
+	vkApiVersion.cpp
+	vkApiVersion.hpp
+	vkBuilderUtil.cpp
+	vkBuilderUtil.hpp
+	vkDefs.cpp
+	vkDefs.hpp
+	vkRef.cpp
+	vkRef.hpp
+	vkRefUtil.cpp
+	vkRefUtil.hpp
+	vkPlatform.cpp
+	vkPlatform.hpp
+	vkPrograms.cpp
+	vkPrograms.hpp
+	vkStrUtil.cpp
+	vkStrUtil.hpp
+	vkQueryUtil.cpp
+	vkQueryUtil.hpp
+	vkMemUtil.cpp
+	vkMemUtil.hpp
+	vkDeviceUtil.cpp
+	vkDeviceUtil.hpp
+	vkGlslToSpirV.cpp
+	vkGlslToSpirV.hpp
+	vkSpirVAsm.hpp
+	vkSpirVAsm.cpp
+	vkSpirVProgram.hpp
+	vkSpirVProgram.cpp
+	vkBinaryRegistry.cpp
+	vkBinaryRegistry.hpp
+	vkNullDriver.cpp
+	vkNullDriver.hpp
+	vkImageUtil.cpp
+	vkImageUtil.hpp
+	vkTypeUtil.cpp
+	vkTypeUtil.hpp
+	)
+
+set(VKUTIL_LIBS
+	glutil
+	tcutil
+	)
+
+if (DEQP_HAVE_GLSLANG)
+	include_directories(${GLSLANG_INCLUDE_PATH})
+	add_definitions(-DDEQP_HAVE_GLSLANG=1)
+
+	# \note Code interfacing with glslang needs to include third-party headers
+	#       that cause all sorts of warnings to appear.
+	if (DE_COMPILER_IS_GCC OR DE_COMPILER_IS_CLANG)
+		set_source_files_properties(
+			FILES vkGlslToSpirV.cpp
+			PROPERTIES COMPILE_FLAGS "${DE_3RD_PARTY_CXX_FLAGS} -std=c++11")
+	endif ()
+
+	set(VKUTIL_LIBS ${VKUTIL_LIBS} ${GLSLANG_LIBRARY})
+endif ()
+
+if(DEQP_HAVE_SPIRV_TOOLS)
+	include_directories(${spirv-tools_SOURCE_DIR}/include)
+	include_directories(${spirv-tools_SOURCE_DIR}/external/include)
+
+	add_definitions(-DDEQP_HAVE_SPIRV_TOOLS=1)
+	set(VKUTIL_LIBS ${VKUTIL_LIBS} SPIRV-TOOLS)
+endif()
+
+add_library(vkutil STATIC ${VKUTIL_SRCS})
+target_link_libraries(vkutil ${VKUTIL_LIBS})
diff --git a/external/vulkancts/framework/vulkan/vkApiVersion.cpp b/external/vulkancts/framework/vulkan/vkApiVersion.cpp
new file mode 100644
index 0000000..2eae4ba
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkApiVersion.cpp
@@ -0,0 +1,56 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan api version.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkApiVersion.hpp"
+
+namespace vk
+{
+
+ApiVersion unpackVersion (deUint32 version)
+{
+	return ApiVersion((version & 0xFFC00000) >> 22,
+					  (version & 0x003FF000) >> 12,
+					   version & 0x00000FFF);
+}
+
+deUint32 pack (const ApiVersion& version)
+{
+	DE_ASSERT((version.majorNum & ~0x3FF) == 0);
+	DE_ASSERT((version.minorNum & ~0x3FF) == 0);
+	DE_ASSERT((version.patchNum & ~0xFFF) == 0);
+
+	return (version.majorNum << 22) | (version.minorNum << 12) | version.patchNum;
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkApiVersion.hpp b/external/vulkancts/framework/vulkan/vkApiVersion.hpp
new file mode 100644
index 0000000..68d1f7b
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkApiVersion.hpp
@@ -0,0 +1,70 @@
+#ifndef _VKAPIVERSION_HPP
+#define _VKAPIVERSION_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan api version.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+#include <ostream>
+
+namespace vk
+{
+
+struct ApiVersion
+{
+	deUint32	majorNum;
+	deUint32	minorNum;
+	deUint32	patchNum;
+
+	ApiVersion (deUint32	majorNum_,
+				deUint32	minorNum_,
+				deUint32	patchNum_)
+		: majorNum	(majorNum_)
+		, minorNum	(minorNum_)
+		, patchNum	(patchNum_)
+	{
+	}
+};
+
+ApiVersion		unpackVersion		(deUint32 version);
+deUint32		pack				(const ApiVersion& version);
+
+inline std::ostream& operator<< (std::ostream& s, const ApiVersion& version)
+{
+	return s << version.majorNum << "." << version.minorNum << "." << version.patchNum;
+}
+
+} // vk
+
+#endif // _VKAPIVERSION_HPP
diff --git a/external/vulkancts/framework/vulkan/vkBasicTypes.inl b/external/vulkancts/framework/vulkan/vkBasicTypes.inl
new file mode 100644
index 0000000..3f84e34
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkBasicTypes.inl
@@ -0,0 +1,986 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+enum { VK_API_VERSION				= VK_MAKE_VERSION(0, 170, 2)	};
+enum { VK_MAX_PHYSICAL_DEVICE_NAME	= 256							};
+enum { VK_MAX_EXTENSION_NAME		= 256							};
+enum { VK_UUID_LENGTH				= 16							};
+enum { VK_MAX_MEMORY_TYPES			= 32							};
+enum { VK_MAX_MEMORY_HEAPS			= 16							};
+enum { VK_MAX_DESCRIPTION			= 256							};
+enum { VK_FALSE						= 0								};
+enum { VK_TRUE						= 1								};
+enum { VK_ATTACHMENT_UNUSED			= (~0U)							};
+
+VK_DEFINE_HANDLE			(VkInstance,			HANDLE_TYPE_INSTANCE);
+VK_DEFINE_HANDLE			(VkPhysicalDevice,		HANDLE_TYPE_PHYSICAL_DEVICE);
+VK_DEFINE_HANDLE			(VkDevice,				HANDLE_TYPE_DEVICE);
+VK_DEFINE_HANDLE			(VkQueue,				HANDLE_TYPE_QUEUE);
+VK_DEFINE_HANDLE			(VkCmdBuffer,			HANDLE_TYPE_CMD_BUFFER);
+VK_DEFINE_NONDISP_HANDLE	(VkFence,				HANDLE_TYPE_FENCE);
+VK_DEFINE_NONDISP_HANDLE	(VkDeviceMemory,		HANDLE_TYPE_DEVICE_MEMORY);
+VK_DEFINE_NONDISP_HANDLE	(VkBuffer,				HANDLE_TYPE_BUFFER);
+VK_DEFINE_NONDISP_HANDLE	(VkImage,				HANDLE_TYPE_IMAGE);
+VK_DEFINE_NONDISP_HANDLE	(VkSemaphore,			HANDLE_TYPE_SEMAPHORE);
+VK_DEFINE_NONDISP_HANDLE	(VkEvent,				HANDLE_TYPE_EVENT);
+VK_DEFINE_NONDISP_HANDLE	(VkQueryPool,			HANDLE_TYPE_QUERY_POOL);
+VK_DEFINE_NONDISP_HANDLE	(VkBufferView,			HANDLE_TYPE_BUFFER_VIEW);
+VK_DEFINE_NONDISP_HANDLE	(VkImageView,			HANDLE_TYPE_IMAGE_VIEW);
+VK_DEFINE_NONDISP_HANDLE	(VkShaderModule,		HANDLE_TYPE_SHADER_MODULE);
+VK_DEFINE_NONDISP_HANDLE	(VkShader,				HANDLE_TYPE_SHADER);
+VK_DEFINE_NONDISP_HANDLE	(VkPipelineCache,		HANDLE_TYPE_PIPELINE_CACHE);
+VK_DEFINE_NONDISP_HANDLE	(VkPipelineLayout,		HANDLE_TYPE_PIPELINE_LAYOUT);
+VK_DEFINE_NONDISP_HANDLE	(VkRenderPass,			HANDLE_TYPE_RENDER_PASS);
+VK_DEFINE_NONDISP_HANDLE	(VkPipeline,			HANDLE_TYPE_PIPELINE);
+VK_DEFINE_NONDISP_HANDLE	(VkDescriptorSetLayout,	HANDLE_TYPE_DESCRIPTOR_SET_LAYOUT);
+VK_DEFINE_NONDISP_HANDLE	(VkSampler,				HANDLE_TYPE_SAMPLER);
+VK_DEFINE_NONDISP_HANDLE	(VkDescriptorPool,		HANDLE_TYPE_DESCRIPTOR_POOL);
+VK_DEFINE_NONDISP_HANDLE	(VkDescriptorSet,		HANDLE_TYPE_DESCRIPTOR_SET);
+VK_DEFINE_NONDISP_HANDLE	(VkFramebuffer,			HANDLE_TYPE_FRAMEBUFFER);
+VK_DEFINE_NONDISP_HANDLE	(VkCmdPool,				HANDLE_TYPE_CMD_POOL);
+
+enum VkResult
+{
+	VK_SUCCESS						= 0,
+	VK_UNSUPPORTED					= 1,
+	VK_NOT_READY					= 2,
+	VK_TIMEOUT						= 3,
+	VK_EVENT_SET					= 4,
+	VK_EVENT_RESET					= 5,
+	VK_INCOMPLETE					= 6,
+	VK_ERROR_OUT_OF_HOST_MEMORY		= -1,
+	VK_ERROR_OUT_OF_DEVICE_MEMORY	= -2,
+	VK_ERROR_INITIALIZATION_FAILED	= -3,
+	VK_ERROR_DEVICE_LOST			= -4,
+	VK_ERROR_MEMORY_MAP_FAILED		= -5,
+	VK_ERROR_LAYER_NOT_PRESENT		= -6,
+	VK_ERROR_EXTENSION_NOT_PRESENT	= -7,
+	VK_ERROR_INCOMPATIBLE_DRIVER	= -8,
+};
+
+enum VkStructureType
+{
+	VK_STRUCTURE_TYPE_APPLICATION_INFO							= 0,
+	VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO						= 1,
+	VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO							= 2,
+	VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO					= 3,
+	VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO					= 4,
+	VK_STRUCTURE_TYPE_SHADER_CREATE_INFO						= 5,
+	VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO				= 6,
+	VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO						= 7,
+	VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO			= 8,
+	VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO					= 9,
+	VK_STRUCTURE_TYPE_EVENT_CREATE_INFO							= 10,
+	VK_STRUCTURE_TYPE_FENCE_CREATE_INFO							= 11,
+	VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO						= 12,
+	VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO					= 13,
+	VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO			= 14,
+	VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO				= 15,
+	VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO	= 16,
+	VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO	= 17,
+	VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO	= 18,
+	VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO		= 19,
+	VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO			= 20,
+	VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO	= 21,
+	VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO	= 22,
+	VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO	= 23,
+	VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO							= 24,
+	VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO						= 25,
+	VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO					= 26,
+	VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO					= 27,
+	VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO						= 28,
+	VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO					= 29,
+	VK_STRUCTURE_TYPE_MEMORY_BARRIER							= 30,
+	VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER						= 31,
+	VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER						= 32,
+	VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO				= 33,
+	VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET						= 34,
+	VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET						= 35,
+	VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO						= 36,
+	VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO				= 37,
+	VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE						= 38,
+	VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO				= 39,
+	VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION					= 40,
+	VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION						= 41,
+	VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY						= 42,
+	VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO					= 43,
+	VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO						= 44,
+	VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO					= 45,
+	VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO		= 46,
+
+	VK_STRUCTURE_TYPE_LAST
+};
+
+enum VkSystemAllocType
+{
+	VK_SYSTEM_ALLOC_TYPE_API_OBJECT			= 0,
+	VK_SYSTEM_ALLOC_TYPE_INTERNAL			= 1,
+	VK_SYSTEM_ALLOC_TYPE_INTERNAL_TEMP		= 2,
+	VK_SYSTEM_ALLOC_TYPE_INTERNAL_SHADER	= 3,
+	VK_SYSTEM_ALLOC_TYPE_DEBUG				= 4,
+
+	VK_SYSTEM_ALLOC_TYPE_LAST
+};
+
+enum VkFormat
+{
+	VK_FORMAT_UNDEFINED				= 0,
+	VK_FORMAT_R4G4_UNORM			= 1,
+	VK_FORMAT_R4G4_USCALED			= 2,
+	VK_FORMAT_R4G4B4A4_UNORM		= 3,
+	VK_FORMAT_R4G4B4A4_USCALED		= 4,
+	VK_FORMAT_R5G6B5_UNORM			= 5,
+	VK_FORMAT_R5G6B5_USCALED		= 6,
+	VK_FORMAT_R5G5B5A1_UNORM		= 7,
+	VK_FORMAT_R5G5B5A1_USCALED		= 8,
+	VK_FORMAT_R8_UNORM				= 9,
+	VK_FORMAT_R8_SNORM				= 10,
+	VK_FORMAT_R8_USCALED			= 11,
+	VK_FORMAT_R8_SSCALED			= 12,
+	VK_FORMAT_R8_UINT				= 13,
+	VK_FORMAT_R8_SINT				= 14,
+	VK_FORMAT_R8_SRGB				= 15,
+	VK_FORMAT_R8G8_UNORM			= 16,
+	VK_FORMAT_R8G8_SNORM			= 17,
+	VK_FORMAT_R8G8_USCALED			= 18,
+	VK_FORMAT_R8G8_SSCALED			= 19,
+	VK_FORMAT_R8G8_UINT				= 20,
+	VK_FORMAT_R8G8_SINT				= 21,
+	VK_FORMAT_R8G8_SRGB				= 22,
+	VK_FORMAT_R8G8B8_UNORM			= 23,
+	VK_FORMAT_R8G8B8_SNORM			= 24,
+	VK_FORMAT_R8G8B8_USCALED		= 25,
+	VK_FORMAT_R8G8B8_SSCALED		= 26,
+	VK_FORMAT_R8G8B8_UINT			= 27,
+	VK_FORMAT_R8G8B8_SINT			= 28,
+	VK_FORMAT_R8G8B8_SRGB			= 29,
+	VK_FORMAT_R8G8B8A8_UNORM		= 30,
+	VK_FORMAT_R8G8B8A8_SNORM		= 31,
+	VK_FORMAT_R8G8B8A8_USCALED		= 32,
+	VK_FORMAT_R8G8B8A8_SSCALED		= 33,
+	VK_FORMAT_R8G8B8A8_UINT			= 34,
+	VK_FORMAT_R8G8B8A8_SINT			= 35,
+	VK_FORMAT_R8G8B8A8_SRGB			= 36,
+	VK_FORMAT_R10G10B10A2_UNORM		= 37,
+	VK_FORMAT_R10G10B10A2_SNORM		= 38,
+	VK_FORMAT_R10G10B10A2_USCALED	= 39,
+	VK_FORMAT_R10G10B10A2_SSCALED	= 40,
+	VK_FORMAT_R10G10B10A2_UINT		= 41,
+	VK_FORMAT_R10G10B10A2_SINT		= 42,
+	VK_FORMAT_R16_UNORM				= 43,
+	VK_FORMAT_R16_SNORM				= 44,
+	VK_FORMAT_R16_USCALED			= 45,
+	VK_FORMAT_R16_SSCALED			= 46,
+	VK_FORMAT_R16_UINT				= 47,
+	VK_FORMAT_R16_SINT				= 48,
+	VK_FORMAT_R16_SFLOAT			= 49,
+	VK_FORMAT_R16G16_UNORM			= 50,
+	VK_FORMAT_R16G16_SNORM			= 51,
+	VK_FORMAT_R16G16_USCALED		= 52,
+	VK_FORMAT_R16G16_SSCALED		= 53,
+	VK_FORMAT_R16G16_UINT			= 54,
+	VK_FORMAT_R16G16_SINT			= 55,
+	VK_FORMAT_R16G16_SFLOAT			= 56,
+	VK_FORMAT_R16G16B16_UNORM		= 57,
+	VK_FORMAT_R16G16B16_SNORM		= 58,
+	VK_FORMAT_R16G16B16_USCALED		= 59,
+	VK_FORMAT_R16G16B16_SSCALED		= 60,
+	VK_FORMAT_R16G16B16_UINT		= 61,
+	VK_FORMAT_R16G16B16_SINT		= 62,
+	VK_FORMAT_R16G16B16_SFLOAT		= 63,
+	VK_FORMAT_R16G16B16A16_UNORM	= 64,
+	VK_FORMAT_R16G16B16A16_SNORM	= 65,
+	VK_FORMAT_R16G16B16A16_USCALED	= 66,
+	VK_FORMAT_R16G16B16A16_SSCALED	= 67,
+	VK_FORMAT_R16G16B16A16_UINT		= 68,
+	VK_FORMAT_R16G16B16A16_SINT		= 69,
+	VK_FORMAT_R16G16B16A16_SFLOAT	= 70,
+	VK_FORMAT_R32_UINT				= 71,
+	VK_FORMAT_R32_SINT				= 72,
+	VK_FORMAT_R32_SFLOAT			= 73,
+	VK_FORMAT_R32G32_UINT			= 74,
+	VK_FORMAT_R32G32_SINT			= 75,
+	VK_FORMAT_R32G32_SFLOAT			= 76,
+	VK_FORMAT_R32G32B32_UINT		= 77,
+	VK_FORMAT_R32G32B32_SINT		= 78,
+	VK_FORMAT_R32G32B32_SFLOAT		= 79,
+	VK_FORMAT_R32G32B32A32_UINT		= 80,
+	VK_FORMAT_R32G32B32A32_SINT		= 81,
+	VK_FORMAT_R32G32B32A32_SFLOAT	= 82,
+	VK_FORMAT_R64_SFLOAT			= 83,
+	VK_FORMAT_R64G64_SFLOAT			= 84,
+	VK_FORMAT_R64G64B64_SFLOAT		= 85,
+	VK_FORMAT_R64G64B64A64_SFLOAT	= 86,
+	VK_FORMAT_R11G11B10_UFLOAT		= 87,
+	VK_FORMAT_R9G9B9E5_UFLOAT		= 88,
+	VK_FORMAT_D16_UNORM				= 89,
+	VK_FORMAT_D24_UNORM_X8			= 90,
+	VK_FORMAT_D32_SFLOAT			= 91,
+	VK_FORMAT_S8_UINT				= 92,
+	VK_FORMAT_D16_UNORM_S8_UINT		= 93,
+	VK_FORMAT_D24_UNORM_S8_UINT		= 94,
+	VK_FORMAT_D32_SFLOAT_S8_UINT	= 95,
+	VK_FORMAT_BC1_RGB_UNORM			= 96,
+	VK_FORMAT_BC1_RGB_SRGB			= 97,
+	VK_FORMAT_BC1_RGBA_UNORM		= 98,
+	VK_FORMAT_BC1_RGBA_SRGB			= 99,
+	VK_FORMAT_BC2_UNORM				= 100,
+	VK_FORMAT_BC2_SRGB				= 101,
+	VK_FORMAT_BC3_UNORM				= 102,
+	VK_FORMAT_BC3_SRGB				= 103,
+	VK_FORMAT_BC4_UNORM				= 104,
+	VK_FORMAT_BC4_SNORM				= 105,
+	VK_FORMAT_BC5_UNORM				= 106,
+	VK_FORMAT_BC5_SNORM				= 107,
+	VK_FORMAT_BC6H_UFLOAT			= 108,
+	VK_FORMAT_BC6H_SFLOAT			= 109,
+	VK_FORMAT_BC7_UNORM				= 110,
+	VK_FORMAT_BC7_SRGB				= 111,
+	VK_FORMAT_ETC2_R8G8B8_UNORM		= 112,
+	VK_FORMAT_ETC2_R8G8B8_SRGB		= 113,
+	VK_FORMAT_ETC2_R8G8B8A1_UNORM	= 114,
+	VK_FORMAT_ETC2_R8G8B8A1_SRGB	= 115,
+	VK_FORMAT_ETC2_R8G8B8A8_UNORM	= 116,
+	VK_FORMAT_ETC2_R8G8B8A8_SRGB	= 117,
+	VK_FORMAT_EAC_R11_UNORM			= 118,
+	VK_FORMAT_EAC_R11_SNORM			= 119,
+	VK_FORMAT_EAC_R11G11_UNORM		= 120,
+	VK_FORMAT_EAC_R11G11_SNORM		= 121,
+	VK_FORMAT_ASTC_4x4_UNORM		= 122,
+	VK_FORMAT_ASTC_4x4_SRGB			= 123,
+	VK_FORMAT_ASTC_5x4_UNORM		= 124,
+	VK_FORMAT_ASTC_5x4_SRGB			= 125,
+	VK_FORMAT_ASTC_5x5_UNORM		= 126,
+	VK_FORMAT_ASTC_5x5_SRGB			= 127,
+	VK_FORMAT_ASTC_6x5_UNORM		= 128,
+	VK_FORMAT_ASTC_6x5_SRGB			= 129,
+	VK_FORMAT_ASTC_6x6_UNORM		= 130,
+	VK_FORMAT_ASTC_6x6_SRGB			= 131,
+	VK_FORMAT_ASTC_8x5_UNORM		= 132,
+	VK_FORMAT_ASTC_8x5_SRGB			= 133,
+	VK_FORMAT_ASTC_8x6_UNORM		= 134,
+	VK_FORMAT_ASTC_8x6_SRGB			= 135,
+	VK_FORMAT_ASTC_8x8_UNORM		= 136,
+	VK_FORMAT_ASTC_8x8_SRGB			= 137,
+	VK_FORMAT_ASTC_10x5_UNORM		= 138,
+	VK_FORMAT_ASTC_10x5_SRGB		= 139,
+	VK_FORMAT_ASTC_10x6_UNORM		= 140,
+	VK_FORMAT_ASTC_10x6_SRGB		= 141,
+	VK_FORMAT_ASTC_10x8_UNORM		= 142,
+	VK_FORMAT_ASTC_10x8_SRGB		= 143,
+	VK_FORMAT_ASTC_10x10_UNORM		= 144,
+	VK_FORMAT_ASTC_10x10_SRGB		= 145,
+	VK_FORMAT_ASTC_12x10_UNORM		= 146,
+	VK_FORMAT_ASTC_12x10_SRGB		= 147,
+	VK_FORMAT_ASTC_12x12_UNORM		= 148,
+	VK_FORMAT_ASTC_12x12_SRGB		= 149,
+	VK_FORMAT_B4G4R4A4_UNORM		= 150,
+	VK_FORMAT_B5G5R5A1_UNORM		= 151,
+	VK_FORMAT_B5G6R5_UNORM			= 152,
+	VK_FORMAT_B5G6R5_USCALED		= 153,
+	VK_FORMAT_B8G8R8_UNORM			= 154,
+	VK_FORMAT_B8G8R8_SNORM			= 155,
+	VK_FORMAT_B8G8R8_USCALED		= 156,
+	VK_FORMAT_B8G8R8_SSCALED		= 157,
+	VK_FORMAT_B8G8R8_UINT			= 158,
+	VK_FORMAT_B8G8R8_SINT			= 159,
+	VK_FORMAT_B8G8R8_SRGB			= 160,
+	VK_FORMAT_B8G8R8A8_UNORM		= 161,
+	VK_FORMAT_B8G8R8A8_SNORM		= 162,
+	VK_FORMAT_B8G8R8A8_USCALED		= 163,
+	VK_FORMAT_B8G8R8A8_SSCALED		= 164,
+	VK_FORMAT_B8G8R8A8_UINT			= 165,
+	VK_FORMAT_B8G8R8A8_SINT			= 166,
+	VK_FORMAT_B8G8R8A8_SRGB			= 167,
+	VK_FORMAT_B10G10R10A2_UNORM		= 168,
+	VK_FORMAT_B10G10R10A2_SNORM		= 169,
+	VK_FORMAT_B10G10R10A2_USCALED	= 170,
+	VK_FORMAT_B10G10R10A2_SSCALED	= 171,
+	VK_FORMAT_B10G10R10A2_UINT		= 172,
+	VK_FORMAT_B10G10R10A2_SINT		= 173,
+
+	VK_FORMAT_LAST
+};
+
+enum VkImageType
+{
+	VK_IMAGE_TYPE_1D	= 0,
+	VK_IMAGE_TYPE_2D	= 1,
+	VK_IMAGE_TYPE_3D	= 2,
+
+	VK_IMAGE_TYPE_LAST
+};
+
+enum VkImageTiling
+{
+	VK_IMAGE_TILING_LINEAR	= 0,
+	VK_IMAGE_TILING_OPTIMAL	= 1,
+
+	VK_IMAGE_TILING_LAST
+};
+
+enum VkPhysicalDeviceType
+{
+	VK_PHYSICAL_DEVICE_TYPE_OTHER			= 0,
+	VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU	= 1,
+	VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU	= 2,
+	VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU		= 3,
+	VK_PHYSICAL_DEVICE_TYPE_CPU				= 4,
+
+	VK_PHYSICAL_DEVICE_TYPE_LAST
+};
+
+enum VkImageAspect
+{
+	VK_IMAGE_ASPECT_COLOR		= 0,
+	VK_IMAGE_ASPECT_DEPTH		= 1,
+	VK_IMAGE_ASPECT_STENCIL		= 2,
+	VK_IMAGE_ASPECT_METADATA	= 3,
+
+	VK_IMAGE_ASPECT_LAST
+};
+
+enum VkQueryType
+{
+	VK_QUERY_TYPE_OCCLUSION				= 0,
+	VK_QUERY_TYPE_PIPELINE_STATISTICS	= 1,
+
+	VK_QUERY_TYPE_LAST
+};
+
+enum VkSharingMode
+{
+	VK_SHARING_MODE_EXCLUSIVE	= 0,
+	VK_SHARING_MODE_CONCURRENT	= 1,
+
+	VK_SHARING_MODE_LAST
+};
+
+enum VkImageLayout
+{
+	VK_IMAGE_LAYOUT_UNDEFINED							= 0,
+	VK_IMAGE_LAYOUT_GENERAL								= 1,
+	VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			= 2,
+	VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL	= 3,
+	VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL		= 4,
+	VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL			= 5,
+	VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL				= 6,
+	VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL		= 7,
+	VK_IMAGE_LAYOUT_PREINITIALIZED						= 8,
+
+	VK_IMAGE_LAYOUT_LAST
+};
+
+enum VkImageViewType
+{
+	VK_IMAGE_VIEW_TYPE_1D			= 0,
+	VK_IMAGE_VIEW_TYPE_2D			= 1,
+	VK_IMAGE_VIEW_TYPE_3D			= 2,
+	VK_IMAGE_VIEW_TYPE_CUBE			= 3,
+	VK_IMAGE_VIEW_TYPE_1D_ARRAY		= 4,
+	VK_IMAGE_VIEW_TYPE_2D_ARRAY		= 5,
+	VK_IMAGE_VIEW_TYPE_CUBE_ARRAY	= 6,
+
+	VK_IMAGE_VIEW_TYPE_LAST
+};
+
+enum VkChannelSwizzle
+{
+	VK_CHANNEL_SWIZZLE_ZERO	= 0,
+	VK_CHANNEL_SWIZZLE_ONE	= 1,
+	VK_CHANNEL_SWIZZLE_R	= 2,
+	VK_CHANNEL_SWIZZLE_G	= 3,
+	VK_CHANNEL_SWIZZLE_B	= 4,
+	VK_CHANNEL_SWIZZLE_A	= 5,
+
+	VK_CHANNEL_SWIZZLE_LAST
+};
+
+enum VkShaderStage
+{
+	VK_SHADER_STAGE_VERTEX			= 0,
+	VK_SHADER_STAGE_TESS_CONTROL	= 1,
+	VK_SHADER_STAGE_TESS_EVALUATION	= 2,
+	VK_SHADER_STAGE_GEOMETRY		= 3,
+	VK_SHADER_STAGE_FRAGMENT		= 4,
+	VK_SHADER_STAGE_COMPUTE			= 5,
+
+	VK_SHADER_STAGE_LAST
+};
+
+enum VkVertexInputStepRate
+{
+	VK_VERTEX_INPUT_STEP_RATE_VERTEX	= 0,
+	VK_VERTEX_INPUT_STEP_RATE_INSTANCE	= 1,
+
+	VK_VERTEX_INPUT_STEP_RATE_LAST
+};
+
+enum VkPrimitiveTopology
+{
+	VK_PRIMITIVE_TOPOLOGY_POINT_LIST			= 0,
+	VK_PRIMITIVE_TOPOLOGY_LINE_LIST				= 1,
+	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP			= 2,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST			= 3,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP		= 4,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN			= 5,
+	VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ			= 6,
+	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ		= 7,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ		= 8,
+	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ	= 9,
+	VK_PRIMITIVE_TOPOLOGY_PATCH					= 10,
+
+	VK_PRIMITIVE_TOPOLOGY_LAST
+};
+
+enum VkFillMode
+{
+	VK_FILL_MODE_POINTS		= 0,
+	VK_FILL_MODE_WIREFRAME	= 1,
+	VK_FILL_MODE_SOLID		= 2,
+
+	VK_FILL_MODE_LAST
+};
+
+enum VkCullMode
+{
+	VK_CULL_MODE_NONE			= 0,
+	VK_CULL_MODE_FRONT			= 1,
+	VK_CULL_MODE_BACK			= 2,
+	VK_CULL_MODE_FRONT_AND_BACK	= 3,
+
+	VK_CULL_MODE_LAST
+};
+
+enum VkFrontFace
+{
+	VK_FRONT_FACE_CCW	= 0,
+	VK_FRONT_FACE_CW	= 1,
+
+	VK_FRONT_FACE_LAST
+};
+
+enum VkCompareOp
+{
+	VK_COMPARE_OP_NEVER			= 0,
+	VK_COMPARE_OP_LESS			= 1,
+	VK_COMPARE_OP_EQUAL			= 2,
+	VK_COMPARE_OP_LESS_EQUAL	= 3,
+	VK_COMPARE_OP_GREATER		= 4,
+	VK_COMPARE_OP_NOT_EQUAL		= 5,
+	VK_COMPARE_OP_GREATER_EQUAL	= 6,
+	VK_COMPARE_OP_ALWAYS		= 7,
+
+	VK_COMPARE_OP_LAST
+};
+
+enum VkStencilOp
+{
+	VK_STENCIL_OP_KEEP		= 0,
+	VK_STENCIL_OP_ZERO		= 1,
+	VK_STENCIL_OP_REPLACE	= 2,
+	VK_STENCIL_OP_INC_CLAMP	= 3,
+	VK_STENCIL_OP_DEC_CLAMP	= 4,
+	VK_STENCIL_OP_INVERT	= 5,
+	VK_STENCIL_OP_INC_WRAP	= 6,
+	VK_STENCIL_OP_DEC_WRAP	= 7,
+
+	VK_STENCIL_OP_LAST
+};
+
+enum VkLogicOp
+{
+	VK_LOGIC_OP_CLEAR			= 0,
+	VK_LOGIC_OP_AND				= 1,
+	VK_LOGIC_OP_AND_REVERSE		= 2,
+	VK_LOGIC_OP_COPY			= 3,
+	VK_LOGIC_OP_AND_INVERTED	= 4,
+	VK_LOGIC_OP_NOOP			= 5,
+	VK_LOGIC_OP_XOR				= 6,
+	VK_LOGIC_OP_OR				= 7,
+	VK_LOGIC_OP_NOR				= 8,
+	VK_LOGIC_OP_EQUIV			= 9,
+	VK_LOGIC_OP_INVERT			= 10,
+	VK_LOGIC_OP_OR_REVERSE		= 11,
+	VK_LOGIC_OP_COPY_INVERTED	= 12,
+	VK_LOGIC_OP_OR_INVERTED		= 13,
+	VK_LOGIC_OP_NAND			= 14,
+	VK_LOGIC_OP_SET				= 15,
+
+	VK_LOGIC_OP_LAST
+};
+
+enum VkBlend
+{
+	VK_BLEND_ZERO						= 0,
+	VK_BLEND_ONE						= 1,
+	VK_BLEND_SRC_COLOR					= 2,
+	VK_BLEND_ONE_MINUS_SRC_COLOR		= 3,
+	VK_BLEND_DEST_COLOR					= 4,
+	VK_BLEND_ONE_MINUS_DEST_COLOR		= 5,
+	VK_BLEND_SRC_ALPHA					= 6,
+	VK_BLEND_ONE_MINUS_SRC_ALPHA		= 7,
+	VK_BLEND_DEST_ALPHA					= 8,
+	VK_BLEND_ONE_MINUS_DEST_ALPHA		= 9,
+	VK_BLEND_CONSTANT_COLOR				= 10,
+	VK_BLEND_ONE_MINUS_CONSTANT_COLOR	= 11,
+	VK_BLEND_CONSTANT_ALPHA				= 12,
+	VK_BLEND_ONE_MINUS_CONSTANT_ALPHA	= 13,
+	VK_BLEND_SRC_ALPHA_SATURATE			= 14,
+	VK_BLEND_SRC1_COLOR					= 15,
+	VK_BLEND_ONE_MINUS_SRC1_COLOR		= 16,
+	VK_BLEND_SRC1_ALPHA					= 17,
+	VK_BLEND_ONE_MINUS_SRC1_ALPHA		= 18,
+
+	VK_BLEND_LAST
+};
+
+enum VkBlendOp
+{
+	VK_BLEND_OP_ADD					= 0,
+	VK_BLEND_OP_SUBTRACT			= 1,
+	VK_BLEND_OP_REVERSE_SUBTRACT	= 2,
+	VK_BLEND_OP_MIN					= 3,
+	VK_BLEND_OP_MAX					= 4,
+
+	VK_BLEND_OP_LAST
+};
+
+enum VkDynamicState
+{
+	VK_DYNAMIC_STATE_VIEWPORT				= 0,
+	VK_DYNAMIC_STATE_SCISSOR				= 1,
+	VK_DYNAMIC_STATE_LINE_WIDTH				= 2,
+	VK_DYNAMIC_STATE_DEPTH_BIAS				= 3,
+	VK_DYNAMIC_STATE_BLEND_CONSTANTS		= 4,
+	VK_DYNAMIC_STATE_DEPTH_BOUNDS			= 5,
+	VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK	= 6,
+	VK_DYNAMIC_STATE_STENCIL_WRITE_MASK		= 7,
+	VK_DYNAMIC_STATE_STENCIL_REFERENCE		= 8,
+
+	VK_DYNAMIC_STATE_LAST
+};
+
+enum VkTexFilter
+{
+	VK_TEX_FILTER_NEAREST	= 0,
+	VK_TEX_FILTER_LINEAR	= 1,
+
+	VK_TEX_FILTER_LAST
+};
+
+enum VkTexMipmapMode
+{
+	VK_TEX_MIPMAP_MODE_BASE		= 0,
+	VK_TEX_MIPMAP_MODE_NEAREST	= 1,
+	VK_TEX_MIPMAP_MODE_LINEAR	= 2,
+
+	VK_TEX_MIPMAP_MODE_LAST
+};
+
+enum VkTexAddressMode
+{
+	VK_TEX_ADDRESS_MODE_WRAP			= 0,
+	VK_TEX_ADDRESS_MODE_MIRROR			= 1,
+	VK_TEX_ADDRESS_MODE_CLAMP			= 2,
+	VK_TEX_ADDRESS_MODE_MIRROR_ONCE		= 3,
+	VK_TEX_ADDRESS_MODE_CLAMP_BORDER	= 4,
+
+	VK_TEX_ADDRESS_MODE_LAST
+};
+
+enum VkBorderColor
+{
+	VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK	= 0,
+	VK_BORDER_COLOR_INT_TRANSPARENT_BLACK	= 1,
+	VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK		= 2,
+	VK_BORDER_COLOR_INT_OPAQUE_BLACK		= 3,
+	VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE		= 4,
+	VK_BORDER_COLOR_INT_OPAQUE_WHITE		= 5,
+
+	VK_BORDER_COLOR_LAST
+};
+
+enum VkDescriptorType
+{
+	VK_DESCRIPTOR_TYPE_SAMPLER					= 0,
+	VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER	= 1,
+	VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE			= 2,
+	VK_DESCRIPTOR_TYPE_STORAGE_IMAGE			= 3,
+	VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER		= 4,
+	VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER		= 5,
+	VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER			= 6,
+	VK_DESCRIPTOR_TYPE_STORAGE_BUFFER			= 7,
+	VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC	= 8,
+	VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC	= 9,
+	VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT			= 10,
+
+	VK_DESCRIPTOR_TYPE_LAST
+};
+
+enum VkDescriptorPoolUsage
+{
+	VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT	= 0,
+	VK_DESCRIPTOR_POOL_USAGE_DYNAMIC	= 1,
+
+	VK_DESCRIPTOR_POOL_USAGE_LAST
+};
+
+enum VkDescriptorSetUsage
+{
+	VK_DESCRIPTOR_SET_USAGE_ONE_SHOT	= 0,
+	VK_DESCRIPTOR_SET_USAGE_STATIC		= 1,
+
+	VK_DESCRIPTOR_SET_USAGE_LAST
+};
+
+enum VkAttachmentLoadOp
+{
+	VK_ATTACHMENT_LOAD_OP_LOAD		= 0,
+	VK_ATTACHMENT_LOAD_OP_CLEAR		= 1,
+	VK_ATTACHMENT_LOAD_OP_DONT_CARE	= 2,
+
+	VK_ATTACHMENT_LOAD_OP_LAST
+};
+
+enum VkAttachmentStoreOp
+{
+	VK_ATTACHMENT_STORE_OP_STORE		= 0,
+	VK_ATTACHMENT_STORE_OP_DONT_CARE	= 1,
+
+	VK_ATTACHMENT_STORE_OP_LAST
+};
+
+enum VkPipelineBindPoint
+{
+	VK_PIPELINE_BIND_POINT_COMPUTE	= 0,
+	VK_PIPELINE_BIND_POINT_GRAPHICS	= 1,
+
+	VK_PIPELINE_BIND_POINT_LAST
+};
+
+enum VkCmdBufferLevel
+{
+	VK_CMD_BUFFER_LEVEL_PRIMARY		= 0,
+	VK_CMD_BUFFER_LEVEL_SECONDARY	= 1,
+
+	VK_CMD_BUFFER_LEVEL_LAST
+};
+
+enum VkIndexType
+{
+	VK_INDEX_TYPE_UINT16	= 0,
+	VK_INDEX_TYPE_UINT32	= 1,
+
+	VK_INDEX_TYPE_LAST
+};
+
+enum VkTimestampType
+{
+	VK_TIMESTAMP_TYPE_TOP		= 0,
+	VK_TIMESTAMP_TYPE_BOTTOM	= 1,
+
+	VK_TIMESTAMP_TYPE_LAST
+};
+
+enum VkRenderPassContents
+{
+	VK_RENDER_PASS_CONTENTS_INLINE					= 0,
+	VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS	= 1,
+
+	VK_RENDER_PASS_CONTENTS_LAST
+};
+
+enum VkFormatFeatureFlagBits
+{
+	VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT					= 0x00000001,
+	VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT					= 0x00000002,
+	VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT			= 0x00000004,
+	VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT			= 0x00000008,
+	VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT			= 0x00000010,
+	VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT	= 0x00000020,
+	VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT					= 0x00000040,
+	VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT				= 0x00000080,
+	VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT		= 0x00000100,
+	VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT		= 0x00000200,
+	VK_FORMAT_FEATURE_BLIT_SOURCE_BIT					= 0x00000400,
+	VK_FORMAT_FEATURE_BLIT_DESTINATION_BIT				= 0x00000800,
+};
+typedef deUint32 VkFormatFeatureFlags;
+
+enum VkImageUsageFlagBits
+{
+	VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT			= 0x00000001,
+	VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT		= 0x00000002,
+	VK_IMAGE_USAGE_SAMPLED_BIT					= 0x00000004,
+	VK_IMAGE_USAGE_STORAGE_BIT					= 0x00000008,
+	VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT			= 0x00000010,
+	VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT	= 0x00000020,
+	VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT		= 0x00000040,
+	VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT			= 0x00000080,
+};
+typedef deUint32 VkImageUsageFlags;
+
+enum VkImageCreateFlagBits
+{
+	VK_IMAGE_CREATE_SPARSE_BINDING_BIT		= 0x00000001,
+	VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT	= 0x00000002,
+	VK_IMAGE_CREATE_SPARSE_ALIASED_BIT		= 0x00000004,
+	VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT		= 0x00000008,
+	VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT		= 0x00000010,
+};
+typedef deUint32 VkImageCreateFlags;
+
+enum VkSampleCountFlagBits
+{
+	VK_SAMPLE_COUNT_1_BIT	= 0x00000001,
+	VK_SAMPLE_COUNT_2_BIT	= 0x00000002,
+	VK_SAMPLE_COUNT_4_BIT	= 0x00000004,
+	VK_SAMPLE_COUNT_8_BIT	= 0x00000008,
+	VK_SAMPLE_COUNT_16_BIT	= 0x00000010,
+	VK_SAMPLE_COUNT_32_BIT	= 0x00000020,
+	VK_SAMPLE_COUNT_64_BIT	= 0x00000040,
+};
+typedef deUint32 VkSampleCountFlags;
+
+enum VkQueueFlagBits
+{
+	VK_QUEUE_GRAPHICS_BIT		= 0x00000001,
+	VK_QUEUE_COMPUTE_BIT		= 0x00000002,
+	VK_QUEUE_DMA_BIT			= 0x00000004,
+	VK_QUEUE_SPARSE_MEMMGR_BIT	= 0x00000008,
+	VK_QUEUE_EXTENDED_BIT		= 0x40000000,
+};
+typedef deUint32 VkQueueFlags;
+
+enum VkMemoryPropertyFlagBits
+{
+	VK_MEMORY_PROPERTY_DEVICE_ONLY				= 0,
+	VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT			= 0x00000001,
+	VK_MEMORY_PROPERTY_HOST_NON_COHERENT_BIT	= 0x00000002,
+	VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT		= 0x00000004,
+	VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT	= 0x00000008,
+	VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT		= 0x00000010,
+};
+typedef deUint32 VkMemoryPropertyFlags;
+
+enum VkMemoryHeapFlagBits
+{
+	VK_MEMORY_HEAP_HOST_LOCAL_BIT	= 0x00000001,
+};
+typedef deUint32 VkMemoryHeapFlags;
+
+enum VkSparseImageFormatFlagBits
+{
+	VK_SPARSE_IMAGE_FMT_SINGLE_MIPTAIL_BIT		= 0x00000001,
+	VK_SPARSE_IMAGE_FMT_ALIGNED_MIP_SIZE_BIT	= 0x00000002,
+	VK_SPARSE_IMAGE_FMT_NONSTD_BLOCK_SIZE_BIT	= 0x00000004,
+};
+typedef deUint32 VkSparseImageFormatFlags;
+
+enum VkSparseMemoryBindFlagBits
+{
+	VK_SPARSE_MEMORY_BIND_REPLICATE_64KIB_BLOCK_BIT	= 0x00000001,
+};
+typedef deUint32 VkSparseMemoryBindFlags;
+
+enum VkFenceCreateFlagBits
+{
+	VK_FENCE_CREATE_SIGNALED_BIT	= 0x00000001,
+};
+typedef deUint32 VkFenceCreateFlags;
+
+enum VkQueryPipelineStatisticFlagBits
+{
+	VK_QUERY_PIPELINE_STATISTIC_IA_VERTICES_BIT		= 0x00000001,
+	VK_QUERY_PIPELINE_STATISTIC_IA_PRIMITIVES_BIT	= 0x00000002,
+	VK_QUERY_PIPELINE_STATISTIC_VS_INVOCATIONS_BIT	= 0x00000004,
+	VK_QUERY_PIPELINE_STATISTIC_GS_INVOCATIONS_BIT	= 0x00000008,
+	VK_QUERY_PIPELINE_STATISTIC_GS_PRIMITIVES_BIT	= 0x00000010,
+	VK_QUERY_PIPELINE_STATISTIC_C_INVOCATIONS_BIT	= 0x00000020,
+	VK_QUERY_PIPELINE_STATISTIC_C_PRIMITIVES_BIT	= 0x00000040,
+	VK_QUERY_PIPELINE_STATISTIC_FS_INVOCATIONS_BIT	= 0x00000080,
+	VK_QUERY_PIPELINE_STATISTIC_TCS_PATCHES_BIT		= 0x00000100,
+	VK_QUERY_PIPELINE_STATISTIC_TES_INVOCATIONS_BIT	= 0x00000200,
+	VK_QUERY_PIPELINE_STATISTIC_CS_INVOCATIONS_BIT	= 0x00000400,
+};
+typedef deUint32 VkQueryPipelineStatisticFlags;
+
+enum VkQueryResultFlagBits
+{
+	VK_QUERY_RESULT_DEFAULT					= 0,
+	VK_QUERY_RESULT_64_BIT					= 0x00000001,
+	VK_QUERY_RESULT_WAIT_BIT				= 0x00000002,
+	VK_QUERY_RESULT_WITH_AVAILABILITY_BIT	= 0x00000004,
+	VK_QUERY_RESULT_PARTIAL_BIT				= 0x00000008,
+};
+typedef deUint32 VkQueryResultFlags;
+
+enum VkBufferUsageFlagBits
+{
+	VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT			= 0x00000001,
+	VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT	= 0x00000002,
+	VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT	= 0x00000004,
+	VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT	= 0x00000008,
+	VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT			= 0x00000010,
+	VK_BUFFER_USAGE_STORAGE_BUFFER_BIT			= 0x00000020,
+	VK_BUFFER_USAGE_INDEX_BUFFER_BIT			= 0x00000040,
+	VK_BUFFER_USAGE_VERTEX_BUFFER_BIT			= 0x00000080,
+	VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT			= 0x00000100,
+};
+typedef deUint32 VkBufferUsageFlags;
+
+enum VkBufferCreateFlagBits
+{
+	VK_BUFFER_CREATE_SPARSE_BINDING_BIT		= 0x00000001,
+	VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT	= 0x00000002,
+	VK_BUFFER_CREATE_SPARSE_ALIASED_BIT		= 0x00000004,
+};
+typedef deUint32 VkBufferCreateFlags;
+
+enum VkImageAspectFlagBits
+{
+	VK_IMAGE_ASPECT_COLOR_BIT		= 0x00000001,
+	VK_IMAGE_ASPECT_DEPTH_BIT		= 0x00000002,
+	VK_IMAGE_ASPECT_STENCIL_BIT		= 0x00000004,
+	VK_IMAGE_ASPECT_METADATA_BIT	= 0x00000008,
+};
+typedef deUint32 VkImageAspectFlags;
+
+enum VkImageViewCreateFlagBits
+{
+	VK_IMAGE_VIEW_CREATE_READ_ONLY_DEPTH_BIT	= 0x00000001,
+	VK_IMAGE_VIEW_CREATE_READ_ONLY_STENCIL_BIT	= 0x00000002,
+};
+typedef deUint32 VkImageViewCreateFlags;
+
+enum VkChannelFlagBits
+{
+	VK_CHANNEL_R_BIT	= 0x00000001,
+	VK_CHANNEL_G_BIT	= 0x00000002,
+	VK_CHANNEL_B_BIT	= 0x00000004,
+	VK_CHANNEL_A_BIT	= 0x00000008,
+};
+typedef deUint32 VkChannelFlags;
+
+enum VkPipelineCreateFlagBits
+{
+	VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT	= 0x00000001,
+	VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT	= 0x00000002,
+	VK_PIPELINE_CREATE_DERIVATIVE_BIT			= 0x00000004,
+};
+typedef deUint32 VkPipelineCreateFlags;
+
+enum VkShaderStageFlagBits
+{
+	VK_SHADER_STAGE_VERTEX_BIT			= 0x00000001,
+	VK_SHADER_STAGE_TESS_CONTROL_BIT	= 0x00000002,
+	VK_SHADER_STAGE_TESS_EVALUATION_BIT	= 0x00000004,
+	VK_SHADER_STAGE_GEOMETRY_BIT		= 0x00000008,
+	VK_SHADER_STAGE_FRAGMENT_BIT		= 0x00000010,
+	VK_SHADER_STAGE_COMPUTE_BIT			= 0x00000020,
+	VK_SHADER_STAGE_ALL					= 0x7FFFFFFF,
+};
+typedef deUint32 VkShaderStageFlags;
+
+enum VkAttachmentDescriptionFlagBits
+{
+	VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT	= 0x00000001,
+};
+typedef deUint32 VkAttachmentDescriptionFlags;
+
+enum VkSubpassDescriptionFlagBits
+{
+	VK_SUBPASS_DESCRIPTION_NO_OVERDRAW_BIT	= 0x00000001,
+};
+typedef deUint32 VkSubpassDescriptionFlags;
+
+enum VkPipelineStageFlagBits
+{
+	VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT				= 0x00000001,
+	VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT				= 0x00000002,
+	VK_PIPELINE_STAGE_VERTEX_INPUT_BIT				= 0x00000004,
+	VK_PIPELINE_STAGE_VERTEX_SHADER_BIT				= 0x00000008,
+	VK_PIPELINE_STAGE_TESS_CONTROL_SHADER_BIT		= 0x00000010,
+	VK_PIPELINE_STAGE_TESS_EVALUATION_SHADER_BIT	= 0x00000020,
+	VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT			= 0x00000040,
+	VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT			= 0x00000080,
+	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT		= 0x00000100,
+	VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT		= 0x00000200,
+	VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT	= 0x00000400,
+	VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT			= 0x00000800,
+	VK_PIPELINE_STAGE_TRANSFER_BIT					= 0x00001000,
+	VK_PIPELINE_STAGE_HOST_BIT						= 0x00002000,
+	VK_PIPELINE_STAGE_ALL_GRAPHICS					= 0x000007FF,
+	VK_PIPELINE_STAGE_ALL_GPU_COMMANDS				= 0x00001FFF,
+};
+typedef deUint32 VkPipelineStageFlags;
+
+enum VkMemoryOutputFlagBits
+{
+	VK_MEMORY_OUTPUT_HOST_WRITE_BIT					= 0x00000001,
+	VK_MEMORY_OUTPUT_SHADER_WRITE_BIT				= 0x00000002,
+	VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT			= 0x00000004,
+	VK_MEMORY_OUTPUT_DEPTH_STENCIL_ATTACHMENT_BIT	= 0x00000008,
+	VK_MEMORY_OUTPUT_TRANSFER_BIT					= 0x00000010,
+};
+typedef deUint32 VkMemoryOutputFlags;
+
+enum VkMemoryInputFlagBits
+{
+	VK_MEMORY_INPUT_HOST_READ_BIT					= 0x00000001,
+	VK_MEMORY_INPUT_INDIRECT_COMMAND_BIT			= 0x00000002,
+	VK_MEMORY_INPUT_INDEX_FETCH_BIT					= 0x00000004,
+	VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT		= 0x00000008,
+	VK_MEMORY_INPUT_UNIFORM_READ_BIT				= 0x00000010,
+	VK_MEMORY_INPUT_SHADER_READ_BIT					= 0x00000020,
+	VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT			= 0x00000040,
+	VK_MEMORY_INPUT_DEPTH_STENCIL_ATTACHMENT_BIT	= 0x00000080,
+	VK_MEMORY_INPUT_INPUT_ATTACHMENT_BIT			= 0x00000100,
+	VK_MEMORY_INPUT_TRANSFER_BIT					= 0x00000200,
+};
+typedef deUint32 VkMemoryInputFlags;
+
+enum VkCmdPoolCreateFlagBits
+{
+	VK_CMD_POOL_CREATE_TRANSIENT_BIT			= 0x00000001,
+	VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT	= 0x00000002,
+};
+typedef deUint32 VkCmdPoolCreateFlags;
+
+enum VkCmdPoolResetFlagBits
+{
+	VK_CMD_POOL_RESET_RELEASE_RESOURCES_BIT	= 0x00000001,
+};
+typedef deUint32 VkCmdPoolResetFlags;
+
+enum VkCmdBufferOptimizeFlagBits
+{
+	VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT				= 0x00000001,
+	VK_CMD_BUFFER_OPTIMIZE_PIPELINE_SWITCH_BIT			= 0x00000002,
+	VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT			= 0x00000004,
+	VK_CMD_BUFFER_OPTIMIZE_DESCRIPTOR_SET_SWITCH_BIT	= 0x00000008,
+	VK_CMD_BUFFER_OPTIMIZE_NO_SIMULTANEOUS_USE_BIT		= 0x00000010,
+};
+typedef deUint32 VkCmdBufferOptimizeFlags;
+
+enum VkCmdBufferResetFlagBits
+{
+	VK_CMD_BUFFER_RESET_RELEASE_RESOURCES_BIT	= 0x00000001,
+};
+typedef deUint32 VkCmdBufferResetFlags;
+
+enum VkStencilFaceFlagBits
+{
+	VK_STENCIL_FACE_NONE		= 0,
+	VK_STENCIL_FACE_FRONT_BIT	= 0x00000001,
+	VK_STENCIL_FACE_BACK_BIT	= 0x00000002,
+};
+typedef deUint32 VkStencilFaceFlags;
+
+enum VkQueryControlFlagBits
+{
+	VK_QUERY_CONTROL_CONSERVATIVE_BIT	= 0x00000001,
+};
+typedef deUint32 VkQueryControlFlags;
+
diff --git a/external/vulkancts/framework/vulkan/vkBinaryRegistry.cpp b/external/vulkancts/framework/vulkan/vkBinaryRegistry.cpp
new file mode 100644
index 0000000..b247583
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkBinaryRegistry.cpp
@@ -0,0 +1,126 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Program binary registry.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkBinaryRegistry.hpp"
+#include "tcuResource.hpp"
+#include "deFilePath.hpp"
+#include "deStringUtil.hpp"
+
+#include <fstream>
+#include <sstream>
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+
+static string getProgramPath (const ProgramIdentifier& id)
+{
+	const vector<string>	casePathComps	= de::splitString(id.testCasePath, '.');
+	std::ostringstream		path;
+
+	for (size_t compNdx = 0; compNdx < casePathComps.size(); compNdx++)
+		path << casePathComps[compNdx] << '/';
+
+	path << id.programName << ".spv";
+
+	return path.str();
+}
+
+// BinaryRegistryWriter
+
+BinaryRegistryWriter::BinaryRegistryWriter (const std::string& dstPath)
+	: m_dstPath(dstPath)
+{
+}
+
+BinaryRegistryWriter::~BinaryRegistryWriter (void)
+{
+}
+
+void BinaryRegistryWriter::storeProgram (const ProgramIdentifier& id, const ProgramBinary& binary)
+{
+	const de::FilePath	fullPath	= de::FilePath::join(m_dstPath, getProgramPath(id));
+
+	if (!de::FilePath(fullPath.getDirName()).exists())
+		de::createDirectoryAndParents(fullPath.getDirName().c_str());
+
+	{
+		std::ofstream	out		(fullPath.getPath(), std::ios_base::binary);
+
+		if (!out.is_open() || !out.good())
+			throw tcu::Exception("Failed to open " + string(fullPath.getPath()));
+
+		out.write((const char*)binary.getBinary(), binary.getSize());
+		out.close();
+	}
+}
+
+// BinaryRegistryReader
+
+BinaryRegistryReader::BinaryRegistryReader (const tcu::Archive& archive, const std::string& srcPath)
+	: m_archive	(archive)
+	, m_srcPath	(srcPath)
+{
+}
+
+BinaryRegistryReader::~BinaryRegistryReader (void)
+{
+}
+
+ProgramBinary* BinaryRegistryReader::loadProgram (const ProgramIdentifier& id) const
+{
+	const string	fullPath	= de::FilePath::join(m_srcPath, getProgramPath(id)).getPath();
+
+	try
+	{
+		de::UniquePtr<tcu::Resource>	progRes		(m_archive.getResource(fullPath.c_str()));
+		const int						progSize	= progRes->getSize();
+		vector<deUint8>					bytes		(progSize);
+
+		TCU_CHECK_INTERNAL(!bytes.empty());
+
+		progRes->read(&bytes[0], progSize);
+
+		return new ProgramBinary(vk::PROGRAM_FORMAT_SPIRV, bytes.size(), &bytes[0]);
+	}
+	catch (const tcu::ResourceError&)
+	{
+		throw ProgramNotFoundException(id);
+	}
+}
+
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkBinaryRegistry.hpp b/external/vulkancts/framework/vulkan/vkBinaryRegistry.hpp
new file mode 100644
index 0000000..ede6d72
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkBinaryRegistry.hpp
@@ -0,0 +1,96 @@
+#ifndef _VKBINARYREGISTRY_HPP
+#define _VKBINARYREGISTRY_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Program binary registry.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkPrograms.hpp"
+
+namespace tcu
+{
+class Archive;
+}
+
+namespace vk
+{
+
+struct ProgramIdentifier
+{
+	std::string		testCasePath;
+	std::string		programName;
+
+	ProgramIdentifier (const std::string& testCasePath_, const std::string& programName_)
+		: testCasePath	(testCasePath_)
+		, programName	(programName_)
+	{
+	}
+};
+
+class ProgramNotFoundException : public tcu::ResourceError
+{
+public:
+	ProgramNotFoundException (const ProgramIdentifier& id)
+		: tcu::ResourceError("Program " + id.testCasePath + " / '" + id.programName + "' not found")
+	{
+	}
+};
+
+class BinaryRegistryReader
+{
+public:
+						BinaryRegistryReader	(const tcu::Archive& archive, const std::string& srcPath);
+						~BinaryRegistryReader	(void);
+
+	ProgramBinary*		loadProgram				(const ProgramIdentifier& id) const;
+
+private:
+	const tcu::Archive&	m_archive;
+	const std::string	m_srcPath;
+};
+
+class BinaryRegistryWriter
+{
+public:
+						BinaryRegistryWriter	(const std::string& dstPath);
+						~BinaryRegistryWriter	(void);
+
+	void				storeProgram			(const ProgramIdentifier& id, const ProgramBinary& binary);
+
+private:
+	const std::string	m_dstPath;
+};
+
+} // vk
+
+#endif // _VKBINARYREGISTRY_HPP
diff --git a/external/vulkancts/framework/vulkan/vkBuilderUtil.cpp b/external/vulkancts/framework/vulkan/vkBuilderUtil.cpp
new file mode 100644
index 0000000..287bd08
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkBuilderUtil.cpp
@@ -0,0 +1,193 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object builder utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkBuilderUtil.hpp"
+
+#include "vkRefUtil.hpp"
+
+namespace vk
+{
+
+// DescriptorSetLayoutBuilder
+
+DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder (void)
+{
+}
+
+DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::addBinding (VkDescriptorType	descriptorType,
+																	deUint32			arraySize,
+																	VkShaderStageFlags	stageFlags,
+																	const VkSampler*	pImmutableSamplers)
+{
+	const VkDescriptorSetLayoutBinding binding =
+	{
+		descriptorType,			//!< descriptorType
+		arraySize,				//!< arraySize
+		stageFlags,				//!< stageFlags
+		pImmutableSamplers,		//!< pImmutableSamplers
+	};
+	m_bindings.push_back(binding);
+	return *this;
+}
+
+Move<VkDescriptorSetLayout> DescriptorSetLayoutBuilder::build (const DeviceInterface& vk, VkDevice device) const
+{
+	const VkDescriptorSetLayoutBinding* const	bindingPtr	= (m_bindings.empty()) ? (DE_NULL) : (&m_bindings[0]);
+	const VkDescriptorSetLayoutCreateInfo		createInfo	=
+	{
+		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		(deUint32)m_bindings.size(),		//!< count
+		bindingPtr,							//!< pBinding
+	};
+
+	return createDescriptorSetLayout(vk, device, &createInfo);
+}
+
+// DescriptorPoolBuilder
+
+DescriptorPoolBuilder::DescriptorPoolBuilder (void)
+{
+}
+
+DescriptorPoolBuilder& DescriptorPoolBuilder::addType (VkDescriptorType type, deUint32 numDescriptors)
+{
+	if (numDescriptors == 0u)
+	{
+		// nothing to do
+		return *this;
+	}
+	else
+	{
+		for (size_t ndx = 0; ndx < m_counts.size(); ++ndx)
+		{
+			if (m_counts[ndx].type == type)
+			{
+				// augment existing requirement
+				m_counts[ndx].count += numDescriptors;
+				return *this;
+			}
+		}
+
+		{
+			// new requirement
+			const VkDescriptorTypeCount typeCount =
+			{
+				type,			//!< type
+				numDescriptors,	//!< count
+			};
+
+			m_counts.push_back(typeCount);
+			return *this;
+		}
+	}
+}
+
+Move<VkDescriptorPool> DescriptorPoolBuilder::build (const DeviceInterface& vk, VkDevice device, VkDescriptorPoolUsage poolUsage, deUint32 maxSets) const
+{
+	const VkDescriptorTypeCount* const	typeCountPtr	= (m_counts.empty()) ? (DE_NULL) : (&m_counts[0]);
+	const VkDescriptorPoolCreateInfo	createInfo		=
+	{
+		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+		DE_NULL,
+		poolUsage,
+		maxSets,
+		(deUint32)m_counts.size(),		//!< count
+		typeCountPtr,					//!< pTypeCount
+	};
+
+	return createDescriptorPool(vk, device, &createInfo);
+}
+
+// DescriptorSetUpdateBuilder
+
+DescriptorSetUpdateBuilder::DescriptorSetUpdateBuilder (void)
+{
+}
+
+DescriptorSetUpdateBuilder& DescriptorSetUpdateBuilder::write (VkDescriptorSet			destSet,
+															   deUint32					destBinding,
+															   deUint32					destArrayElement,
+															   deUint32					count,
+															   VkDescriptorType			descriptorType,
+															   const VkDescriptorInfo*	pDescriptors)
+{
+	const VkWriteDescriptorSet writeParams =
+	{
+		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+		DE_NULL,
+		destSet,			//!< destSet
+		destBinding,		//!< destBinding
+		destArrayElement,	//!< destArrayElement
+		count,				//!< count
+		descriptorType,		//!< descriptorType
+		pDescriptors,		//!< pDescriptors
+	};
+	m_writes.push_back(writeParams);
+	return *this;
+}
+
+DescriptorSetUpdateBuilder& DescriptorSetUpdateBuilder::copy (VkDescriptorSet	srcSet,
+															  deUint32			srcBinding,
+															  deUint32			srcArrayElement,
+															  VkDescriptorSet	destSet,
+															  deUint32			destBinding,
+															  deUint32			destArrayElement,
+															  deUint32			count)
+{
+	const VkCopyDescriptorSet copyParams =
+	{
+		VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
+		DE_NULL,
+		srcSet,				//!< srcSet
+		srcBinding,			//!< srcBinding
+		srcArrayElement,	//!< srcArrayElement
+		destSet,			//!< destSet
+		destBinding,		//!< destBinding
+		destArrayElement,	//!< destArrayElement
+		count,				//!< count
+	};
+	m_copies.push_back(copyParams);
+	return *this;
+}
+
+void DescriptorSetUpdateBuilder::update (const DeviceInterface& vk, VkDevice device) const
+{
+	const VkWriteDescriptorSet* const	writePtr	= (m_writes.empty()) ? (DE_NULL) : (&m_writes[0]);
+	const VkCopyDescriptorSet* const	copyPtr		= (m_copies.empty()) ? (DE_NULL) : (&m_copies[0]);
+
+	vk.updateDescriptorSets(device, (deUint32)m_writes.size(), writePtr, (deUint32)m_copies.size(), copyPtr);
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkBuilderUtil.hpp b/external/vulkancts/framework/vulkan/vkBuilderUtil.hpp
new file mode 100644
index 0000000..e63ac95
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkBuilderUtil.hpp
@@ -0,0 +1,202 @@
+#ifndef _VKBUILDERUTIL_HPP
+#define _VKBUILDERUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object builder utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+
+#include <vector>
+
+namespace vk
+{
+
+class DescriptorSetLayoutBuilder
+{
+public:
+												DescriptorSetLayoutBuilder	(void);
+
+	DescriptorSetLayoutBuilder&					addBinding					(VkDescriptorType	descriptorType,
+																			 deUint32			arraySize,
+																			 VkShaderStageFlags	stageFlags,
+																			 const VkSampler*	pImmutableSamplers);
+
+	Move<VkDescriptorSetLayout>					build						(const DeviceInterface& vk, VkDevice device) const;
+
+	// helpers
+
+	inline DescriptorSetLayoutBuilder&			addSingleBinding			(VkDescriptorType	descriptorType,
+																			 VkShaderStageFlags	stageFlags)
+	{
+		return addBinding(descriptorType, 1u, stageFlags, (VkSampler*)DE_NULL);
+	}
+	inline DescriptorSetLayoutBuilder&			addArrayBinding				(VkDescriptorType	descriptorType,
+																			 deUint32			arraySize,
+																			 VkShaderStageFlags	stageFlags)
+	{
+		return addBinding(descriptorType, arraySize, stageFlags, (VkSampler*)DE_NULL);
+	}
+	inline DescriptorSetLayoutBuilder&			addSingleSamplerBinding		(VkDescriptorType	descriptorType,
+																			 VkShaderStageFlags	stageFlags,
+																			 const VkSampler*	immutableSampler)	//!< \note: Using pointer to sampler to clarify that handle is not
+																													//!<        copied and argument lifetime is expected to cover build()
+																													//!<        call.
+	{
+		return addBinding(descriptorType, 1u, stageFlags, immutableSampler);
+	}
+	inline DescriptorSetLayoutBuilder&			addArraySamplerBinding		(VkDescriptorType	descriptorType,
+																			 deUint32			arraySize,
+																			 VkShaderStageFlags	stageFlags,
+																			 const VkSampler*	pImmutableSamplers)
+	{
+		return addBinding(descriptorType, arraySize, stageFlags, pImmutableSamplers);
+	}
+
+private:
+												DescriptorSetLayoutBuilder	(const DescriptorSetLayoutBuilder&); // delete
+	DescriptorSetLayoutBuilder&					operator=					(const DescriptorSetLayoutBuilder&); // delete
+
+	std::vector<VkDescriptorSetLayoutBinding>	m_bindings;
+};
+
+class DescriptorPoolBuilder
+{
+public:
+										DescriptorPoolBuilder	(void);
+
+	DescriptorPoolBuilder&				addType					(VkDescriptorType type, deUint32 numDescriptors = 1u);
+	Move<VkDescriptorPool>				build					(const DeviceInterface& vk, VkDevice device, VkDescriptorPoolUsage poolUsage, deUint32 maxSets) const;
+
+private:
+										DescriptorPoolBuilder	(const DescriptorPoolBuilder&); // delete
+	DescriptorPoolBuilder&				operator=				(const DescriptorPoolBuilder&); // delete
+
+	std::vector<VkDescriptorTypeCount>	m_counts;
+};
+
+class DescriptorSetUpdateBuilder
+{
+public:
+	class Location
+	{
+	public:
+		static inline Location	binding				(deUint32 binding_)
+		{
+			return Location(binding_, 0u);
+		}
+		static inline Location	bindingArrayElement	(deUint32 binding_, deUint32 arrayElement)
+		{
+			return Location(binding_, arrayElement);
+		}
+
+	private:
+		// \note private to force use of factory methods that have more descriptive names
+		inline					Location			(deUint32 binding_, deUint32 arrayElement)
+			: m_binding			(binding_)
+			, m_arrayElement	(arrayElement)
+		{
+		}
+
+		friend class DescriptorSetUpdateBuilder;
+
+		const deUint32			m_binding;
+		const deUint32			m_arrayElement;
+	};
+
+										DescriptorSetUpdateBuilder	(void);
+
+	DescriptorSetUpdateBuilder&			write						(VkDescriptorSet			destSet,
+																	 deUint32					destBinding,
+																	 deUint32					destArrayElement,
+																	 deUint32					count,
+																	 VkDescriptorType			descriptorType,
+																	 const VkDescriptorInfo*	pDescriptors);
+
+	DescriptorSetUpdateBuilder&			copy						(VkDescriptorSet	srcSet,
+																	 deUint32			srcBinding,
+																	 deUint32			srcArrayElement,
+																	 VkDescriptorSet	destSet,
+																	 deUint32			destBinding,
+																	 deUint32			destArrayElement,
+																	 deUint32			count);
+
+	void								update						(const DeviceInterface& vk, VkDevice device) const;
+
+	// helpers
+
+	inline DescriptorSetUpdateBuilder&	writeSingle					(VkDescriptorSet			destSet,
+																	 const Location&			destLocation,
+																	 VkDescriptorType			descriptorType,
+																	 const VkDescriptorInfo*	descriptor)
+	{
+		return write(destSet, destLocation.m_binding, destLocation.m_arrayElement, 1u, descriptorType, descriptor);
+	}
+
+	inline DescriptorSetUpdateBuilder&	writeArray					(VkDescriptorSet			destSet,
+																	 const Location&			destLocation,
+																	 VkDescriptorType			descriptorType,
+																	 deUint32					numDescriptors,
+																	 const VkDescriptorInfo*	descriptors)
+	{
+		return write(destSet, destLocation.m_binding, destLocation.m_arrayElement, numDescriptors, descriptorType, descriptors);
+	}
+
+	inline DescriptorSetUpdateBuilder&	copySingle					(VkDescriptorSet	srcSet,
+																	 const Location&	srcLocation,
+																	 VkDescriptorSet	destSet,
+																	 const Location&	destLocation)
+	{
+		return copy(srcSet, srcLocation.m_binding, srcLocation.m_arrayElement, destSet, destLocation.m_binding, destLocation.m_arrayElement, 1u);
+	}
+
+	inline DescriptorSetUpdateBuilder&	copyArray					(VkDescriptorSet	srcSet,
+																	 const Location&	srcLocation,
+																	 VkDescriptorSet	destSet,
+																	 const Location&	destLocation,
+																	 deUint32			count)
+	{
+		return copy(srcSet, srcLocation.m_binding, srcLocation.m_arrayElement, destSet, destLocation.m_binding, destLocation.m_arrayElement, count);
+	}
+
+private:
+										DescriptorSetUpdateBuilder	(const DescriptorSetUpdateBuilder&); // delete
+	DescriptorSetUpdateBuilder&			operator=					(const DescriptorSetUpdateBuilder&); // delete
+
+	std::vector<VkWriteDescriptorSet>	m_writes;
+	std::vector<VkCopyDescriptorSet>	m_copies;
+};
+
+} // vk
+
+#endif // _VKBUILDERUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkConcreteDeviceInterface.inl b/external/vulkancts/framework/vulkan/vkConcreteDeviceInterface.inl
new file mode 100644
index 0000000..bb45bd9
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkConcreteDeviceInterface.inl
@@ -0,0 +1,132 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual void		destroyDevice									(VkDevice device) const;
+virtual VkResult	getDeviceQueue									(VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex, VkQueue* pQueue) const;
+virtual VkResult	queueSubmit										(VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence) const;
+virtual VkResult	queueWaitIdle									(VkQueue queue) const;
+virtual VkResult	deviceWaitIdle									(VkDevice device) const;
+virtual VkResult	allocMemory										(VkDevice device, const VkMemoryAllocInfo* pAllocInfo, VkDeviceMemory* pMem) const;
+virtual void		freeMemory										(VkDevice device, VkDeviceMemory mem) const;
+virtual VkResult	mapMemory										(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) const;
+virtual void		unmapMemory										(VkDevice device, VkDeviceMemory mem) const;
+virtual VkResult	flushMappedMemoryRanges							(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const;
+virtual VkResult	invalidateMappedMemoryRanges					(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const;
+virtual VkResult	getDeviceMemoryCommitment						(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) const;
+virtual VkResult	bindBufferMemory								(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) const;
+virtual VkResult	bindImageMemory									(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) const;
+virtual VkResult	getBufferMemoryRequirements						(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) const;
+virtual VkResult	getImageMemoryRequirements						(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) const;
+virtual VkResult	getImageSparseMemoryRequirements				(VkDevice device, VkImage image, deUint32* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) const;
+virtual VkResult	getPhysicalDeviceSparseImageFormatProperties	(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, deUint32 samples, VkImageUsageFlags usage, VkImageTiling tiling, deUint32* pNumProperties, VkSparseImageFormatProperties* pProperties) const;
+virtual VkResult	queueBindSparseBufferMemory						(VkQueue queue, VkBuffer buffer, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const;
+virtual VkResult	queueBindSparseImageOpaqueMemory				(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const;
+virtual VkResult	queueBindSparseImageMemory						(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseImageMemoryBindInfo* pBindInfo) const;
+virtual VkResult	createFence										(VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence) const;
+virtual void		destroyFence									(VkDevice device, VkFence fence) const;
+virtual VkResult	resetFences										(VkDevice device, deUint32 fenceCount, const VkFence* pFences) const;
+virtual VkResult	getFenceStatus									(VkDevice device, VkFence fence) const;
+virtual VkResult	waitForFences									(VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout) const;
+virtual VkResult	createSemaphore									(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore) const;
+virtual void		destroySemaphore								(VkDevice device, VkSemaphore semaphore) const;
+virtual VkResult	queueSignalSemaphore							(VkQueue queue, VkSemaphore semaphore) const;
+virtual VkResult	queueWaitSemaphore								(VkQueue queue, VkSemaphore semaphore) const;
+virtual VkResult	createEvent										(VkDevice device, const VkEventCreateInfo* pCreateInfo, VkEvent* pEvent) const;
+virtual void		destroyEvent									(VkDevice device, VkEvent event) const;
+virtual VkResult	getEventStatus									(VkDevice device, VkEvent event) const;
+virtual VkResult	setEvent										(VkDevice device, VkEvent event) const;
+virtual VkResult	resetEvent										(VkDevice device, VkEvent event) const;
+virtual VkResult	createQueryPool									(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, VkQueryPool* pQueryPool) const;
+virtual void		destroyQueryPool								(VkDevice device, VkQueryPool queryPool) const;
+virtual VkResult	getQueryPoolResults								(VkDevice device, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, deUintptr* pDataSize, void* pData, VkQueryResultFlags flags) const;
+virtual VkResult	createBuffer									(VkDevice device, const VkBufferCreateInfo* pCreateInfo, VkBuffer* pBuffer) const;
+virtual void		destroyBuffer									(VkDevice device, VkBuffer buffer) const;
+virtual VkResult	createBufferView								(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, VkBufferView* pView) const;
+virtual void		destroyBufferView								(VkDevice device, VkBufferView bufferView) const;
+virtual VkResult	createImage										(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage) const;
+virtual void		destroyImage									(VkDevice device, VkImage image) const;
+virtual VkResult	getImageSubresourceLayout						(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const;
+virtual VkResult	createImageView									(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView) const;
+virtual void		destroyImageView								(VkDevice device, VkImageView imageView) const;
+virtual VkResult	createShaderModule								(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule) const;
+virtual void		destroyShaderModule								(VkDevice device, VkShaderModule shaderModule) const;
+virtual VkResult	createShader									(VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader) const;
+virtual void		destroyShader									(VkDevice device, VkShader shader) const;
+virtual VkResult	createPipelineCache								(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache) const;
+virtual void		destroyPipelineCache							(VkDevice device, VkPipelineCache pipelineCache) const;
+virtual deUintptr	getPipelineCacheSize							(VkDevice device, VkPipelineCache pipelineCache) const;
+virtual VkResult	getPipelineCacheData							(VkDevice device, VkPipelineCache pipelineCache, void* pData) const;
+virtual VkResult	mergePipelineCaches								(VkDevice device, VkPipelineCache destCache, deUint32 srcCacheCount, const VkPipelineCache* pSrcCaches) const;
+virtual VkResult	createGraphicsPipelines							(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const;
+virtual VkResult	createComputePipelines							(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const;
+virtual void		destroyPipeline									(VkDevice device, VkPipeline pipeline) const;
+virtual VkResult	createPipelineLayout							(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout) const;
+virtual void		destroyPipelineLayout							(VkDevice device, VkPipelineLayout pipelineLayout) const;
+virtual VkResult	createSampler									(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler) const;
+virtual void		destroySampler									(VkDevice device, VkSampler sampler) const;
+virtual VkResult	createDescriptorSetLayout						(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout) const;
+virtual void		destroyDescriptorSetLayout						(VkDevice device, VkDescriptorSetLayout descriptorSetLayout) const;
+virtual VkResult	createDescriptorPool							(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorPool* pDescriptorPool) const;
+virtual void		destroyDescriptorPool							(VkDevice device, VkDescriptorPool descriptorPool) const;
+virtual VkResult	resetDescriptorPool								(VkDevice device, VkDescriptorPool descriptorPool) const;
+virtual VkResult	allocDescriptorSets								(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, deUint32 count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets) const;
+virtual VkResult	freeDescriptorSets								(VkDevice device, VkDescriptorPool descriptorPool, deUint32 count, const VkDescriptorSet* pDescriptorSets) const;
+virtual void		updateDescriptorSets							(VkDevice device, deUint32 writeCount, const VkWriteDescriptorSet* pDescriptorWrites, deUint32 copyCount, const VkCopyDescriptorSet* pDescriptorCopies) const;
+virtual VkResult	createFramebuffer								(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, VkFramebuffer* pFramebuffer) const;
+virtual void		destroyFramebuffer								(VkDevice device, VkFramebuffer framebuffer) const;
+virtual VkResult	createRenderPass								(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass) const;
+virtual void		destroyRenderPass								(VkDevice device, VkRenderPass renderPass) const;
+virtual VkResult	getRenderAreaGranularity						(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) const;
+virtual VkResult	createCommandPool								(VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo, VkCmdPool* pCmdPool) const;
+virtual void		destroyCommandPool								(VkDevice device, VkCmdPool cmdPool) const;
+virtual VkResult	resetCommandPool								(VkDevice device, VkCmdPool cmdPool, VkCmdPoolResetFlags flags) const;
+virtual VkResult	createCommandBuffer								(VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, VkCmdBuffer* pCmdBuffer) const;
+virtual void		destroyCommandBuffer							(VkDevice device, VkCmdBuffer commandBuffer) const;
+virtual VkResult	beginCommandBuffer								(VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo) const;
+virtual VkResult	endCommandBuffer								(VkCmdBuffer cmdBuffer) const;
+virtual VkResult	resetCommandBuffer								(VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags) const;
+virtual void		cmdBindPipeline									(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) const;
+virtual void		cmdSetViewport									(VkCmdBuffer cmdBuffer, deUint32 viewportCount, const VkViewport* pViewports) const;
+virtual void		cmdSetScissor									(VkCmdBuffer cmdBuffer, deUint32 scissorCount, const VkRect2D* pScissors) const;
+virtual void		cmdSetLineWidth									(VkCmdBuffer cmdBuffer, float lineWidth) const;
+virtual void		cmdSetDepthBias									(VkCmdBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias) const;
+virtual void		cmdSetBlendConstants							(VkCmdBuffer cmdBuffer, const float blendConst[4]) const;
+virtual void		cmdSetDepthBounds								(VkCmdBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds) const;
+virtual void		cmdSetStencilCompareMask						(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilCompareMask) const;
+virtual void		cmdSetStencilWriteMask							(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilWriteMask) const;
+virtual void		cmdSetStencilReference							(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilReference) const;
+virtual void		cmdBindDescriptorSets							(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, deUint32 firstSet, deUint32 setCount, const VkDescriptorSet* pDescriptorSets, deUint32 dynamicOffsetCount, const deUint32* pDynamicOffsets) const;
+virtual void		cmdBindIndexBuffer								(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) const;
+virtual void		cmdBindVertexBuffers							(VkCmdBuffer cmdBuffer, deUint32 startBinding, deUint32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) const;
+virtual void		cmdDraw											(VkCmdBuffer cmdBuffer, deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance) const;
+virtual void		cmdDrawIndexed									(VkCmdBuffer cmdBuffer, deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance) const;
+virtual void		cmdDrawIndirect									(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const;
+virtual void		cmdDrawIndexedIndirect							(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const;
+virtual void		cmdDispatch										(VkCmdBuffer cmdBuffer, deUint32 x, deUint32 y, deUint32 z) const;
+virtual void		cmdDispatchIndirect								(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset) const;
+virtual void		cmdCopyBuffer									(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, deUint32 regionCount, const VkBufferCopy* pRegions) const;
+virtual void		cmdCopyImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageCopy* pRegions) const;
+virtual void		cmdBlitImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageBlit* pRegions, VkTexFilter filter) const;
+virtual void		cmdCopyBufferToImage							(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkBufferImageCopy* pRegions) const;
+virtual void		cmdCopyImageToBuffer							(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, deUint32 regionCount, const VkBufferImageCopy* pRegions) const;
+virtual void		cmdUpdateBuffer									(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const deUint32* pData) const;
+virtual void		cmdFillBuffer									(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, deUint32 data) const;
+virtual void		cmdClearColorImage								(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const;
+virtual void		cmdClearDepthStencilImage						(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const;
+virtual void		cmdClearColorAttachment							(VkCmdBuffer cmdBuffer, deUint32 colorAttachment, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rectCount, const VkRect3D* pRects) const;
+virtual void		cmdClearDepthStencilAttachment					(VkCmdBuffer cmdBuffer, VkImageAspectFlags aspectMask, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rectCount, const VkRect3D* pRects) const;
+virtual void		cmdResolveImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageResolve* pRegions) const;
+virtual void		cmdSetEvent										(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const;
+virtual void		cmdResetEvent									(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const;
+virtual void		cmdWaitEvents									(VkCmdBuffer cmdBuffer, deUint32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, deUint32 memBarrierCount, const void* const* ppMemBarriers) const;
+virtual void		cmdPipelineBarrier								(VkCmdBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, VkBool32 byRegion, deUint32 memBarrierCount, const void* const* ppMemBarriers) const;
+virtual void		cmdBeginQuery									(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot, VkQueryControlFlags flags) const;
+virtual void		cmdEndQuery										(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot) const;
+virtual void		cmdResetQueryPool								(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount) const;
+virtual void		cmdWriteTimestamp								(VkCmdBuffer cmdBuffer, VkTimestampType timestampType, VkBuffer destBuffer, VkDeviceSize destOffset) const;
+virtual void		cmdCopyQueryPoolResults							(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags) const;
+virtual void		cmdPushConstants								(VkCmdBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, deUint32 start, deUint32 length, const void* values) const;
+virtual void		cmdBeginRenderPass								(VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents) const;
+virtual void		cmdNextSubpass									(VkCmdBuffer cmdBuffer, VkRenderPassContents contents) const;
+virtual void		cmdEndRenderPass								(VkCmdBuffer cmdBuffer) const;
+virtual void		cmdExecuteCommands								(VkCmdBuffer cmdBuffer, deUint32 cmdBuffersCount, const VkCmdBuffer* pCmdBuffers) const;
diff --git a/external/vulkancts/framework/vulkan/vkConcreteInstanceInterface.inl b/external/vulkancts/framework/vulkan/vkConcreteInstanceInterface.inl
new file mode 100644
index 0000000..55cdbaa
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkConcreteInstanceInterface.inl
@@ -0,0 +1,15 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual void				destroyInstance							(VkInstance instance) const;
+virtual VkResult			enumeratePhysicalDevices				(VkInstance instance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) const;
+virtual VkResult			getPhysicalDeviceFeatures				(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) const;
+virtual VkResult			getPhysicalDeviceFormatProperties		(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) const;
+virtual VkResult			getPhysicalDeviceImageFormatProperties	(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) const;
+virtual VkResult			getPhysicalDeviceProperties				(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) const;
+virtual VkResult			getPhysicalDeviceQueueFamilyProperties	(VkPhysicalDevice physicalDevice, deUint32* pCount, VkQueueFamilyProperties* pQueueFamilyProperties) const;
+virtual VkResult			getPhysicalDeviceMemoryProperties		(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) const;
+virtual PFN_vkVoidFunction	getDeviceProcAddr						(VkDevice device, const char* pName) const;
+virtual VkResult			createDevice							(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice) const;
+virtual VkResult			enumerateDeviceExtensionProperties		(VkPhysicalDevice physicalDevice, const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const;
+virtual VkResult			enumerateDeviceLayerProperties			(VkPhysicalDevice physicalDevice, deUint32* pCount, VkLayerProperties* pProperties) const;
diff --git a/external/vulkancts/framework/vulkan/vkConcretePlatformInterface.inl b/external/vulkancts/framework/vulkan/vkConcretePlatformInterface.inl
new file mode 100644
index 0000000..88c36c7
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkConcretePlatformInterface.inl
@@ -0,0 +1,7 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual VkResult			createInstance							(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance) const;
+virtual PFN_vkVoidFunction	getInstanceProcAddr						(VkInstance instance, const char* pName) const;
+virtual VkResult			enumerateInstanceExtensionProperties	(const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const;
+virtual VkResult			enumerateInstanceLayerProperties		(deUint32* pCount, VkLayerProperties* pProperties) const;
diff --git a/external/vulkancts/framework/vulkan/vkDefs.cpp b/external/vulkancts/framework/vulkan/vkDefs.cpp
new file mode 100644
index 0000000..fc09ec3
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDefs.cpp
@@ -0,0 +1,107 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan utilites.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkStrUtil.hpp"
+
+#include <sstream>
+
+DE_STATIC_ASSERT(sizeof(vk::VkImageType)	== sizeof(deUint32));
+DE_STATIC_ASSERT(sizeof(vk::VkResult)		== sizeof(deUint32));
+DE_STATIC_ASSERT(sizeof(vk::VkDevice)		== sizeof(void*));
+DE_STATIC_ASSERT(sizeof(vk::VkBuffer)		== sizeof(deUint64));
+
+namespace vk
+{
+
+static bool isOutOfMemoryError (VkResult result)
+{
+	return result == VK_ERROR_OUT_OF_DEVICE_MEMORY	||
+		   result == VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+Error::Error (VkResult error, const char* message, const char* expr, const char* file, int line)
+	: tcu::TestError	(message, expr, file, line)
+	, m_error			(error)
+{
+}
+
+Error::Error (VkResult error, const std::string& message)
+	: tcu::TestError	(message)
+	, m_error			(error)
+{
+}
+
+Error::~Error (void) throw()
+{
+}
+
+OutOfMemoryError::OutOfMemoryError (VkResult error, const char* message, const char* expr, const char* file, int line)
+	: tcu::ResourceError(message, expr, file, line)
+	, m_error			(error)
+{
+	DE_ASSERT(isOutOfMemoryError(error));
+}
+
+OutOfMemoryError::OutOfMemoryError (VkResult error, const std::string& message)
+	: tcu::ResourceError(message)
+	, m_error			(error)
+{
+	DE_ASSERT(isOutOfMemoryError(error));
+}
+
+OutOfMemoryError::~OutOfMemoryError (void) throw()
+{
+}
+
+void checkResult (VkResult result, const char* msg, const char* file, int line)
+{
+	if (result != VK_SUCCESS)
+	{
+		std::ostringstream msgStr;
+		if (msg)
+			msgStr << msg << ": ";
+
+		msgStr << getResultStr(result);
+
+		if (isOutOfMemoryError(result))
+			throw OutOfMemoryError(result, msgStr.str().c_str(), DE_NULL, file, line);
+		else if (result == VK_UNSUPPORTED)
+			throw tcu::NotSupportedError(msgStr.str().c_str(), DE_NULL, file, line);
+		else
+			throw Error(result, msgStr.str().c_str(), DE_NULL, file, line);
+	}
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkDefs.hpp b/external/vulkancts/framework/vulkan/vkDefs.hpp
new file mode 100644
index 0000000..ca35084
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDefs.hpp
@@ -0,0 +1,192 @@
+#ifndef _VKDEFS_HPP
+#define _VKDEFS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan utilites.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+
+#if (DE_OS == DE_OS_ANDROID)
+#	include <sys/cdefs.h>
+#	if !defined(__NDK_FPABI__)
+#		define __NDK_FPABI__
+#	endif
+#	define VK_APICALL __NDK_FPABI__
+#else
+#	define VK_APICALL
+#endif
+
+#if (DE_OS == DE_OS_WIN32) && (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
+#	define VK_APIENTRY __stdcall
+#else
+#	define VK_APIENTRY
+#endif
+
+#define VK_DEFINE_HANDLE(NAME, TYPE)			typedef struct NAME##_s* NAME
+#define VK_DEFINE_NONDISP_HANDLE(NAME, TYPE)	typedef Handle<TYPE> NAME
+
+#define VK_MAKE_VERSION(MAJOR, MINOR, PATCH)	((MAJOR << 22) | (MINOR << 12) | PATCH)
+#define VK_BIT(NUM)								(1<<NUM)
+
+#define VK_CHECK(EXPR)							vk::checkResult((EXPR), #EXPR, __FILE__, __LINE__)
+#define VK_CHECK_MSG(EXPR, MSG)					vk::checkResult((EXPR), MSG, __FILE__, __LINE__)
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Vulkan utilities
+ *//*--------------------------------------------------------------------*/
+namespace vk
+{
+
+typedef deUint64	VkDeviceSize;
+typedef deUint32	VkSampleMask;
+typedef deUint32	VkBool32;
+
+typedef deUint32	VkShaderCreateFlags;		// Reserved
+typedef deUint32	VkEventCreateFlags;			// Reserved
+typedef deUint32	VkCmdBufferCreateFlags;		// Reserved
+typedef deUint32	VkSemaphoreCreateFlags;		// Reserved
+typedef deUint32	VkShaderModuleCreateFlags;	// Reserved
+typedef deUint32	VkMemoryMapFlags;			// \todo [2015-05-08 pyry] Reserved? Not documented
+
+// enum HandleType { HANDLE_TYPE_INSTANCE, ... };
+#include "vkHandleType.inl"
+
+template<HandleType Type>
+class Handle
+{
+public:
+				Handle		(void) {} // \note Left uninitialized on purpose
+				Handle		(deUint64 internal) : m_internal(internal) {}
+
+	Handle&		operator=	(deUint64 internal)					{ m_internal = internal; return *this;			}
+
+	bool		operator==	(const Handle<Type>& other) const	{ return this->m_internal == other.m_internal;	}
+	bool		operator!=	(const Handle<Type>& other) const	{ return this->m_internal != other.m_internal;	}
+
+	bool		operator!	(void) const						{ return !m_internal;							}
+
+	deUint64	getInternal	(void) const						{ return m_internal;							}
+
+	enum { HANDLE_TYPE = Type };
+
+private:
+	deUint64	m_internal;
+};
+
+#include "vkBasicTypes.inl"
+
+enum { VK_QUEUE_FAMILY_IGNORED		= 0xffffffff	};
+enum { VK_NO_ATTACHMENT				= 0xffffffff	};
+
+typedef VK_APICALL void		(VK_APIENTRY* PFN_vkVoidFunction)	(void);
+
+typedef VK_APICALL void*	(VK_APIENTRY* PFN_vkAllocFunction)	(void* pUserData, deUintptr size, deUintptr alignment, VkSystemAllocType allocType);
+typedef VK_APICALL void		(VK_APIENTRY* PFN_vkFreeFunction)	(void* pUserData, void* pMem);
+
+#include "vkStructTypes.inl"
+
+extern "C"
+{
+#include "vkFunctionPointerTypes.inl"
+}
+
+class PlatformInterface
+{
+public:
+#include "vkVirtualPlatformInterface.inl"
+
+protected:
+						PlatformInterface	(void) {}
+
+private:
+						PlatformInterface	(const PlatformInterface&);
+	PlatformInterface&	operator=			(const PlatformInterface&);
+};
+
+class InstanceInterface
+{
+public:
+#include "vkVirtualInstanceInterface.inl"
+
+protected:
+						InstanceInterface	(void) {}
+
+private:
+						InstanceInterface	(const InstanceInterface&);
+	InstanceInterface&	operator=			(const InstanceInterface&);
+};
+
+class DeviceInterface
+{
+public:
+#include "vkVirtualDeviceInterface.inl"
+
+protected:
+						DeviceInterface		(void) {}
+
+private:
+						DeviceInterface		(const DeviceInterface&);
+	DeviceInterface&	operator=			(const DeviceInterface&);
+};
+
+class Error : public tcu::TestError
+{
+public:
+					Error				(VkResult error, const char* message, const char* expr, const char* file, int line);
+					Error				(VkResult error, const std::string& message);
+	virtual			~Error				(void) throw();
+
+	VkResult		getError			(void) const { return m_error; }
+
+private:
+	const VkResult	m_error;
+};
+
+class OutOfMemoryError : public tcu::ResourceError
+{
+public:
+					OutOfMemoryError	(VkResult error, const char* message, const char* expr, const char* file, int line);
+					OutOfMemoryError	(VkResult error, const std::string& message);
+	virtual			~OutOfMemoryError	(void) throw();
+
+	VkResult		getError			(void) const { return m_error; }
+
+private:
+	const VkResult	m_error;
+};
+
+void			checkResult			(VkResult result, const char* message, const char* file, int line);
+
+} // vk
+
+#endif // _VKDEFS_HPP
diff --git a/external/vulkancts/framework/vulkan/vkDeviceDriverImpl.inl b/external/vulkancts/framework/vulkan/vkDeviceDriverImpl.inl
new file mode 100644
index 0000000..984440d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDeviceDriverImpl.inl
@@ -0,0 +1,648 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+
+void DeviceDriver::destroyDevice (VkDevice device) const
+{
+	m_vk.destroyDevice(device);
+}
+
+VkResult DeviceDriver::getDeviceQueue (VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex, VkQueue* pQueue) const
+{
+	return m_vk.getDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
+}
+
+VkResult DeviceDriver::queueSubmit (VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence) const
+{
+	return m_vk.queueSubmit(queue, cmdBufferCount, pCmdBuffers, fence);
+}
+
+VkResult DeviceDriver::queueWaitIdle (VkQueue queue) const
+{
+	return m_vk.queueWaitIdle(queue);
+}
+
+VkResult DeviceDriver::deviceWaitIdle (VkDevice device) const
+{
+	return m_vk.deviceWaitIdle(device);
+}
+
+VkResult DeviceDriver::allocMemory (VkDevice device, const VkMemoryAllocInfo* pAllocInfo, VkDeviceMemory* pMem) const
+{
+	return m_vk.allocMemory(device, pAllocInfo, pMem);
+}
+
+void DeviceDriver::freeMemory (VkDevice device, VkDeviceMemory mem) const
+{
+	m_vk.freeMemory(device, mem);
+}
+
+VkResult DeviceDriver::mapMemory (VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) const
+{
+	return m_vk.mapMemory(device, mem, offset, size, flags, ppData);
+}
+
+void DeviceDriver::unmapMemory (VkDevice device, VkDeviceMemory mem) const
+{
+	m_vk.unmapMemory(device, mem);
+}
+
+VkResult DeviceDriver::flushMappedMemoryRanges (VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const
+{
+	return m_vk.flushMappedMemoryRanges(device, memRangeCount, pMemRanges);
+}
+
+VkResult DeviceDriver::invalidateMappedMemoryRanges (VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const
+{
+	return m_vk.invalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
+}
+
+VkResult DeviceDriver::getDeviceMemoryCommitment (VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) const
+{
+	return m_vk.getDeviceMemoryCommitment(device, memory, pCommittedMemoryInBytes);
+}
+
+VkResult DeviceDriver::bindBufferMemory (VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) const
+{
+	return m_vk.bindBufferMemory(device, buffer, mem, memOffset);
+}
+
+VkResult DeviceDriver::bindImageMemory (VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) const
+{
+	return m_vk.bindImageMemory(device, image, mem, memOffset);
+}
+
+VkResult DeviceDriver::getBufferMemoryRequirements (VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) const
+{
+	return m_vk.getBufferMemoryRequirements(device, buffer, pMemoryRequirements);
+}
+
+VkResult DeviceDriver::getImageMemoryRequirements (VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) const
+{
+	return m_vk.getImageMemoryRequirements(device, image, pMemoryRequirements);
+}
+
+VkResult DeviceDriver::getImageSparseMemoryRequirements (VkDevice device, VkImage image, deUint32* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) const
+{
+	return m_vk.getImageSparseMemoryRequirements(device, image, pNumRequirements, pSparseMemoryRequirements);
+}
+
+VkResult DeviceDriver::getPhysicalDeviceSparseImageFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, deUint32 samples, VkImageUsageFlags usage, VkImageTiling tiling, deUint32* pNumProperties, VkSparseImageFormatProperties* pProperties) const
+{
+	return m_vk.getPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
+}
+
+VkResult DeviceDriver::queueBindSparseBufferMemory (VkQueue queue, VkBuffer buffer, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const
+{
+	return m_vk.queueBindSparseBufferMemory(queue, buffer, numBindings, pBindInfo);
+}
+
+VkResult DeviceDriver::queueBindSparseImageOpaqueMemory (VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const
+{
+	return m_vk.queueBindSparseImageOpaqueMemory(queue, image, numBindings, pBindInfo);
+}
+
+VkResult DeviceDriver::queueBindSparseImageMemory (VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseImageMemoryBindInfo* pBindInfo) const
+{
+	return m_vk.queueBindSparseImageMemory(queue, image, numBindings, pBindInfo);
+}
+
+VkResult DeviceDriver::createFence (VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence) const
+{
+	return m_vk.createFence(device, pCreateInfo, pFence);
+}
+
+void DeviceDriver::destroyFence (VkDevice device, VkFence fence) const
+{
+	m_vk.destroyFence(device, fence);
+}
+
+VkResult DeviceDriver::resetFences (VkDevice device, deUint32 fenceCount, const VkFence* pFences) const
+{
+	return m_vk.resetFences(device, fenceCount, pFences);
+}
+
+VkResult DeviceDriver::getFenceStatus (VkDevice device, VkFence fence) const
+{
+	return m_vk.getFenceStatus(device, fence);
+}
+
+VkResult DeviceDriver::waitForFences (VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout) const
+{
+	return m_vk.waitForFences(device, fenceCount, pFences, waitAll, timeout);
+}
+
+VkResult DeviceDriver::createSemaphore (VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore) const
+{
+	return m_vk.createSemaphore(device, pCreateInfo, pSemaphore);
+}
+
+void DeviceDriver::destroySemaphore (VkDevice device, VkSemaphore semaphore) const
+{
+	m_vk.destroySemaphore(device, semaphore);
+}
+
+VkResult DeviceDriver::queueSignalSemaphore (VkQueue queue, VkSemaphore semaphore) const
+{
+	return m_vk.queueSignalSemaphore(queue, semaphore);
+}
+
+VkResult DeviceDriver::queueWaitSemaphore (VkQueue queue, VkSemaphore semaphore) const
+{
+	return m_vk.queueWaitSemaphore(queue, semaphore);
+}
+
+VkResult DeviceDriver::createEvent (VkDevice device, const VkEventCreateInfo* pCreateInfo, VkEvent* pEvent) const
+{
+	return m_vk.createEvent(device, pCreateInfo, pEvent);
+}
+
+void DeviceDriver::destroyEvent (VkDevice device, VkEvent event) const
+{
+	m_vk.destroyEvent(device, event);
+}
+
+VkResult DeviceDriver::getEventStatus (VkDevice device, VkEvent event) const
+{
+	return m_vk.getEventStatus(device, event);
+}
+
+VkResult DeviceDriver::setEvent (VkDevice device, VkEvent event) const
+{
+	return m_vk.setEvent(device, event);
+}
+
+VkResult DeviceDriver::resetEvent (VkDevice device, VkEvent event) const
+{
+	return m_vk.resetEvent(device, event);
+}
+
+VkResult DeviceDriver::createQueryPool (VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, VkQueryPool* pQueryPool) const
+{
+	return m_vk.createQueryPool(device, pCreateInfo, pQueryPool);
+}
+
+void DeviceDriver::destroyQueryPool (VkDevice device, VkQueryPool queryPool) const
+{
+	m_vk.destroyQueryPool(device, queryPool);
+}
+
+VkResult DeviceDriver::getQueryPoolResults (VkDevice device, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, deUintptr* pDataSize, void* pData, VkQueryResultFlags flags) const
+{
+	return m_vk.getQueryPoolResults(device, queryPool, startQuery, queryCount, pDataSize, pData, flags);
+}
+
+VkResult DeviceDriver::createBuffer (VkDevice device, const VkBufferCreateInfo* pCreateInfo, VkBuffer* pBuffer) const
+{
+	return m_vk.createBuffer(device, pCreateInfo, pBuffer);
+}
+
+void DeviceDriver::destroyBuffer (VkDevice device, VkBuffer buffer) const
+{
+	m_vk.destroyBuffer(device, buffer);
+}
+
+VkResult DeviceDriver::createBufferView (VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, VkBufferView* pView) const
+{
+	return m_vk.createBufferView(device, pCreateInfo, pView);
+}
+
+void DeviceDriver::destroyBufferView (VkDevice device, VkBufferView bufferView) const
+{
+	m_vk.destroyBufferView(device, bufferView);
+}
+
+VkResult DeviceDriver::createImage (VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage) const
+{
+	return m_vk.createImage(device, pCreateInfo, pImage);
+}
+
+void DeviceDriver::destroyImage (VkDevice device, VkImage image) const
+{
+	m_vk.destroyImage(device, image);
+}
+
+VkResult DeviceDriver::getImageSubresourceLayout (VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const
+{
+	return m_vk.getImageSubresourceLayout(device, image, pSubresource, pLayout);
+}
+
+VkResult DeviceDriver::createImageView (VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView) const
+{
+	return m_vk.createImageView(device, pCreateInfo, pView);
+}
+
+void DeviceDriver::destroyImageView (VkDevice device, VkImageView imageView) const
+{
+	m_vk.destroyImageView(device, imageView);
+}
+
+VkResult DeviceDriver::createShaderModule (VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule) const
+{
+	return m_vk.createShaderModule(device, pCreateInfo, pShaderModule);
+}
+
+void DeviceDriver::destroyShaderModule (VkDevice device, VkShaderModule shaderModule) const
+{
+	m_vk.destroyShaderModule(device, shaderModule);
+}
+
+VkResult DeviceDriver::createShader (VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader) const
+{
+	return m_vk.createShader(device, pCreateInfo, pShader);
+}
+
+void DeviceDriver::destroyShader (VkDevice device, VkShader shader) const
+{
+	m_vk.destroyShader(device, shader);
+}
+
+VkResult DeviceDriver::createPipelineCache (VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache) const
+{
+	return m_vk.createPipelineCache(device, pCreateInfo, pPipelineCache);
+}
+
+void DeviceDriver::destroyPipelineCache (VkDevice device, VkPipelineCache pipelineCache) const
+{
+	m_vk.destroyPipelineCache(device, pipelineCache);
+}
+
+deUintptr DeviceDriver::getPipelineCacheSize (VkDevice device, VkPipelineCache pipelineCache) const
+{
+	return m_vk.getPipelineCacheSize(device, pipelineCache);
+}
+
+VkResult DeviceDriver::getPipelineCacheData (VkDevice device, VkPipelineCache pipelineCache, void* pData) const
+{
+	return m_vk.getPipelineCacheData(device, pipelineCache, pData);
+}
+
+VkResult DeviceDriver::mergePipelineCaches (VkDevice device, VkPipelineCache destCache, deUint32 srcCacheCount, const VkPipelineCache* pSrcCaches) const
+{
+	return m_vk.mergePipelineCaches(device, destCache, srcCacheCount, pSrcCaches);
+}
+
+VkResult DeviceDriver::createGraphicsPipelines (VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const
+{
+	return m_vk.createGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
+}
+
+VkResult DeviceDriver::createComputePipelines (VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const
+{
+	return m_vk.createComputePipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
+}
+
+void DeviceDriver::destroyPipeline (VkDevice device, VkPipeline pipeline) const
+{
+	m_vk.destroyPipeline(device, pipeline);
+}
+
+VkResult DeviceDriver::createPipelineLayout (VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout) const
+{
+	return m_vk.createPipelineLayout(device, pCreateInfo, pPipelineLayout);
+}
+
+void DeviceDriver::destroyPipelineLayout (VkDevice device, VkPipelineLayout pipelineLayout) const
+{
+	m_vk.destroyPipelineLayout(device, pipelineLayout);
+}
+
+VkResult DeviceDriver::createSampler (VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler) const
+{
+	return m_vk.createSampler(device, pCreateInfo, pSampler);
+}
+
+void DeviceDriver::destroySampler (VkDevice device, VkSampler sampler) const
+{
+	m_vk.destroySampler(device, sampler);
+}
+
+VkResult DeviceDriver::createDescriptorSetLayout (VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout) const
+{
+	return m_vk.createDescriptorSetLayout(device, pCreateInfo, pSetLayout);
+}
+
+void DeviceDriver::destroyDescriptorSetLayout (VkDevice device, VkDescriptorSetLayout descriptorSetLayout) const
+{
+	m_vk.destroyDescriptorSetLayout(device, descriptorSetLayout);
+}
+
+VkResult DeviceDriver::createDescriptorPool (VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorPool* pDescriptorPool) const
+{
+	return m_vk.createDescriptorPool(device, pCreateInfo, pDescriptorPool);
+}
+
+void DeviceDriver::destroyDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool) const
+{
+	m_vk.destroyDescriptorPool(device, descriptorPool);
+}
+
+VkResult DeviceDriver::resetDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool) const
+{
+	return m_vk.resetDescriptorPool(device, descriptorPool);
+}
+
+VkResult DeviceDriver::allocDescriptorSets (VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, deUint32 count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets) const
+{
+	return m_vk.allocDescriptorSets(device, descriptorPool, setUsage, count, pSetLayouts, pDescriptorSets);
+}
+
+VkResult DeviceDriver::freeDescriptorSets (VkDevice device, VkDescriptorPool descriptorPool, deUint32 count, const VkDescriptorSet* pDescriptorSets) const
+{
+	return m_vk.freeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
+}
+
+void DeviceDriver::updateDescriptorSets (VkDevice device, deUint32 writeCount, const VkWriteDescriptorSet* pDescriptorWrites, deUint32 copyCount, const VkCopyDescriptorSet* pDescriptorCopies) const
+{
+	m_vk.updateDescriptorSets(device, writeCount, pDescriptorWrites, copyCount, pDescriptorCopies);
+}
+
+VkResult DeviceDriver::createFramebuffer (VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, VkFramebuffer* pFramebuffer) const
+{
+	return m_vk.createFramebuffer(device, pCreateInfo, pFramebuffer);
+}
+
+void DeviceDriver::destroyFramebuffer (VkDevice device, VkFramebuffer framebuffer) const
+{
+	m_vk.destroyFramebuffer(device, framebuffer);
+}
+
+VkResult DeviceDriver::createRenderPass (VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass) const
+{
+	return m_vk.createRenderPass(device, pCreateInfo, pRenderPass);
+}
+
+void DeviceDriver::destroyRenderPass (VkDevice device, VkRenderPass renderPass) const
+{
+	m_vk.destroyRenderPass(device, renderPass);
+}
+
+VkResult DeviceDriver::getRenderAreaGranularity (VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) const
+{
+	return m_vk.getRenderAreaGranularity(device, renderPass, pGranularity);
+}
+
+VkResult DeviceDriver::createCommandPool (VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo, VkCmdPool* pCmdPool) const
+{
+	return m_vk.createCommandPool(device, pCreateInfo, pCmdPool);
+}
+
+void DeviceDriver::destroyCommandPool (VkDevice device, VkCmdPool cmdPool) const
+{
+	m_vk.destroyCommandPool(device, cmdPool);
+}
+
+VkResult DeviceDriver::resetCommandPool (VkDevice device, VkCmdPool cmdPool, VkCmdPoolResetFlags flags) const
+{
+	return m_vk.resetCommandPool(device, cmdPool, flags);
+}
+
+VkResult DeviceDriver::createCommandBuffer (VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, VkCmdBuffer* pCmdBuffer) const
+{
+	return m_vk.createCommandBuffer(device, pCreateInfo, pCmdBuffer);
+}
+
+void DeviceDriver::destroyCommandBuffer (VkDevice device, VkCmdBuffer commandBuffer) const
+{
+	m_vk.destroyCommandBuffer(device, commandBuffer);
+}
+
+VkResult DeviceDriver::beginCommandBuffer (VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo) const
+{
+	return m_vk.beginCommandBuffer(cmdBuffer, pBeginInfo);
+}
+
+VkResult DeviceDriver::endCommandBuffer (VkCmdBuffer cmdBuffer) const
+{
+	return m_vk.endCommandBuffer(cmdBuffer);
+}
+
+VkResult DeviceDriver::resetCommandBuffer (VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags) const
+{
+	return m_vk.resetCommandBuffer(cmdBuffer, flags);
+}
+
+void DeviceDriver::cmdBindPipeline (VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) const
+{
+	m_vk.cmdBindPipeline(cmdBuffer, pipelineBindPoint, pipeline);
+}
+
+void DeviceDriver::cmdSetViewport (VkCmdBuffer cmdBuffer, deUint32 viewportCount, const VkViewport* pViewports) const
+{
+	m_vk.cmdSetViewport(cmdBuffer, viewportCount, pViewports);
+}
+
+void DeviceDriver::cmdSetScissor (VkCmdBuffer cmdBuffer, deUint32 scissorCount, const VkRect2D* pScissors) const
+{
+	m_vk.cmdSetScissor(cmdBuffer, scissorCount, pScissors);
+}
+
+void DeviceDriver::cmdSetLineWidth (VkCmdBuffer cmdBuffer, float lineWidth) const
+{
+	m_vk.cmdSetLineWidth(cmdBuffer, lineWidth);
+}
+
+void DeviceDriver::cmdSetDepthBias (VkCmdBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias) const
+{
+	m_vk.cmdSetDepthBias(cmdBuffer, depthBias, depthBiasClamp, slopeScaledDepthBias);
+}
+
+void DeviceDriver::cmdSetBlendConstants (VkCmdBuffer cmdBuffer, const float blendConst[4]) const
+{
+	m_vk.cmdSetBlendConstants(cmdBuffer, blendConst);
+}
+
+void DeviceDriver::cmdSetDepthBounds (VkCmdBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds) const
+{
+	m_vk.cmdSetDepthBounds(cmdBuffer, minDepthBounds, maxDepthBounds);
+}
+
+void DeviceDriver::cmdSetStencilCompareMask (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilCompareMask) const
+{
+	m_vk.cmdSetStencilCompareMask(cmdBuffer, faceMask, stencilCompareMask);
+}
+
+void DeviceDriver::cmdSetStencilWriteMask (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilWriteMask) const
+{
+	m_vk.cmdSetStencilWriteMask(cmdBuffer, faceMask, stencilWriteMask);
+}
+
+void DeviceDriver::cmdSetStencilReference (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilReference) const
+{
+	m_vk.cmdSetStencilReference(cmdBuffer, faceMask, stencilReference);
+}
+
+void DeviceDriver::cmdBindDescriptorSets (VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, deUint32 firstSet, deUint32 setCount, const VkDescriptorSet* pDescriptorSets, deUint32 dynamicOffsetCount, const deUint32* pDynamicOffsets) const
+{
+	m_vk.cmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, layout, firstSet, setCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
+}
+
+void DeviceDriver::cmdBindIndexBuffer (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) const
+{
+	m_vk.cmdBindIndexBuffer(cmdBuffer, buffer, offset, indexType);
+}
+
+void DeviceDriver::cmdBindVertexBuffers (VkCmdBuffer cmdBuffer, deUint32 startBinding, deUint32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) const
+{
+	m_vk.cmdBindVertexBuffers(cmdBuffer, startBinding, bindingCount, pBuffers, pOffsets);
+}
+
+void DeviceDriver::cmdDraw (VkCmdBuffer cmdBuffer, deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance) const
+{
+	m_vk.cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
+}
+
+void DeviceDriver::cmdDrawIndexed (VkCmdBuffer cmdBuffer, deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance) const
+{
+	m_vk.cmdDrawIndexed(cmdBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
+}
+
+void DeviceDriver::cmdDrawIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const
+{
+	m_vk.cmdDrawIndirect(cmdBuffer, buffer, offset, count, stride);
+}
+
+void DeviceDriver::cmdDrawIndexedIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const
+{
+	m_vk.cmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count, stride);
+}
+
+void DeviceDriver::cmdDispatch (VkCmdBuffer cmdBuffer, deUint32 x, deUint32 y, deUint32 z) const
+{
+	m_vk.cmdDispatch(cmdBuffer, x, y, z);
+}
+
+void DeviceDriver::cmdDispatchIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset) const
+{
+	m_vk.cmdDispatchIndirect(cmdBuffer, buffer, offset);
+}
+
+void DeviceDriver::cmdCopyBuffer (VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, deUint32 regionCount, const VkBufferCopy* pRegions) const
+{
+	m_vk.cmdCopyBuffer(cmdBuffer, srcBuffer, destBuffer, regionCount, pRegions);
+}
+
+void DeviceDriver::cmdCopyImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageCopy* pRegions) const
+{
+	m_vk.cmdCopyImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
+}
+
+void DeviceDriver::cmdBlitImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageBlit* pRegions, VkTexFilter filter) const
+{
+	m_vk.cmdBlitImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
+}
+
+void DeviceDriver::cmdCopyBufferToImage (VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkBufferImageCopy* pRegions) const
+{
+	m_vk.cmdCopyBufferToImage(cmdBuffer, srcBuffer, destImage, destImageLayout, regionCount, pRegions);
+}
+
+void DeviceDriver::cmdCopyImageToBuffer (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, deUint32 regionCount, const VkBufferImageCopy* pRegions) const
+{
+	m_vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, srcImageLayout, destBuffer, regionCount, pRegions);
+}
+
+void DeviceDriver::cmdUpdateBuffer (VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const deUint32* pData) const
+{
+	m_vk.cmdUpdateBuffer(cmdBuffer, destBuffer, destOffset, dataSize, pData);
+}
+
+void DeviceDriver::cmdFillBuffer (VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, deUint32 data) const
+{
+	m_vk.cmdFillBuffer(cmdBuffer, destBuffer, destOffset, fillSize, data);
+}
+
+void DeviceDriver::cmdClearColorImage (VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const
+{
+	m_vk.cmdClearColorImage(cmdBuffer, image, imageLayout, pColor, rangeCount, pRanges);
+}
+
+void DeviceDriver::cmdClearDepthStencilImage (VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const
+{
+	m_vk.cmdClearDepthStencilImage(cmdBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
+}
+
+void DeviceDriver::cmdClearColorAttachment (VkCmdBuffer cmdBuffer, deUint32 colorAttachment, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rectCount, const VkRect3D* pRects) const
+{
+	m_vk.cmdClearColorAttachment(cmdBuffer, colorAttachment, imageLayout, pColor, rectCount, pRects);
+}
+
+void DeviceDriver::cmdClearDepthStencilAttachment (VkCmdBuffer cmdBuffer, VkImageAspectFlags aspectMask, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rectCount, const VkRect3D* pRects) const
+{
+	m_vk.cmdClearDepthStencilAttachment(cmdBuffer, aspectMask, imageLayout, pDepthStencil, rectCount, pRects);
+}
+
+void DeviceDriver::cmdResolveImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageResolve* pRegions) const
+{
+	m_vk.cmdResolveImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
+}
+
+void DeviceDriver::cmdSetEvent (VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const
+{
+	m_vk.cmdSetEvent(cmdBuffer, event, stageMask);
+}
+
+void DeviceDriver::cmdResetEvent (VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const
+{
+	m_vk.cmdResetEvent(cmdBuffer, event, stageMask);
+}
+
+void DeviceDriver::cmdWaitEvents (VkCmdBuffer cmdBuffer, deUint32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, deUint32 memBarrierCount, const void* const* ppMemBarriers) const
+{
+	m_vk.cmdWaitEvents(cmdBuffer, eventCount, pEvents, srcStageMask, destStageMask, memBarrierCount, ppMemBarriers);
+}
+
+void DeviceDriver::cmdPipelineBarrier (VkCmdBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, VkBool32 byRegion, deUint32 memBarrierCount, const void* const* ppMemBarriers) const
+{
+	m_vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, destStageMask, byRegion, memBarrierCount, ppMemBarriers);
+}
+
+void DeviceDriver::cmdBeginQuery (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot, VkQueryControlFlags flags) const
+{
+	m_vk.cmdBeginQuery(cmdBuffer, queryPool, slot, flags);
+}
+
+void DeviceDriver::cmdEndQuery (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot) const
+{
+	m_vk.cmdEndQuery(cmdBuffer, queryPool, slot);
+}
+
+void DeviceDriver::cmdResetQueryPool (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount) const
+{
+	m_vk.cmdResetQueryPool(cmdBuffer, queryPool, startQuery, queryCount);
+}
+
+void DeviceDriver::cmdWriteTimestamp (VkCmdBuffer cmdBuffer, VkTimestampType timestampType, VkBuffer destBuffer, VkDeviceSize destOffset) const
+{
+	m_vk.cmdWriteTimestamp(cmdBuffer, timestampType, destBuffer, destOffset);
+}
+
+void DeviceDriver::cmdCopyQueryPoolResults (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags) const
+{
+	m_vk.cmdCopyQueryPoolResults(cmdBuffer, queryPool, startQuery, queryCount, destBuffer, destOffset, destStride, flags);
+}
+
+void DeviceDriver::cmdPushConstants (VkCmdBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, deUint32 start, deUint32 length, const void* values) const
+{
+	m_vk.cmdPushConstants(cmdBuffer, layout, stageFlags, start, length, values);
+}
+
+void DeviceDriver::cmdBeginRenderPass (VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents) const
+{
+	m_vk.cmdBeginRenderPass(cmdBuffer, pRenderPassBegin, contents);
+}
+
+void DeviceDriver::cmdNextSubpass (VkCmdBuffer cmdBuffer, VkRenderPassContents contents) const
+{
+	m_vk.cmdNextSubpass(cmdBuffer, contents);
+}
+
+void DeviceDriver::cmdEndRenderPass (VkCmdBuffer cmdBuffer) const
+{
+	m_vk.cmdEndRenderPass(cmdBuffer);
+}
+
+void DeviceDriver::cmdExecuteCommands (VkCmdBuffer cmdBuffer, deUint32 cmdBuffersCount, const VkCmdBuffer* pCmdBuffers) const
+{
+	m_vk.cmdExecuteCommands(cmdBuffer, cmdBuffersCount, pCmdBuffers);
+}
diff --git a/external/vulkancts/framework/vulkan/vkDeviceFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkDeviceFunctionPointers.inl
new file mode 100644
index 0000000..654a390
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDeviceFunctionPointers.inl
@@ -0,0 +1,132 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+DestroyDeviceFunc									destroyDevice;
+GetDeviceQueueFunc									getDeviceQueue;
+QueueSubmitFunc										queueSubmit;
+QueueWaitIdleFunc									queueWaitIdle;
+DeviceWaitIdleFunc									deviceWaitIdle;
+AllocMemoryFunc										allocMemory;
+FreeMemoryFunc										freeMemory;
+MapMemoryFunc										mapMemory;
+UnmapMemoryFunc										unmapMemory;
+FlushMappedMemoryRangesFunc							flushMappedMemoryRanges;
+InvalidateMappedMemoryRangesFunc					invalidateMappedMemoryRanges;
+GetDeviceMemoryCommitmentFunc						getDeviceMemoryCommitment;
+BindBufferMemoryFunc								bindBufferMemory;
+BindImageMemoryFunc									bindImageMemory;
+GetBufferMemoryRequirementsFunc						getBufferMemoryRequirements;
+GetImageMemoryRequirementsFunc						getImageMemoryRequirements;
+GetImageSparseMemoryRequirementsFunc				getImageSparseMemoryRequirements;
+GetPhysicalDeviceSparseImageFormatPropertiesFunc	getPhysicalDeviceSparseImageFormatProperties;
+QueueBindSparseBufferMemoryFunc						queueBindSparseBufferMemory;
+QueueBindSparseImageOpaqueMemoryFunc				queueBindSparseImageOpaqueMemory;
+QueueBindSparseImageMemoryFunc						queueBindSparseImageMemory;
+CreateFenceFunc										createFence;
+DestroyFenceFunc									destroyFence;
+ResetFencesFunc										resetFences;
+GetFenceStatusFunc									getFenceStatus;
+WaitForFencesFunc									waitForFences;
+CreateSemaphoreFunc									createSemaphore;
+DestroySemaphoreFunc								destroySemaphore;
+QueueSignalSemaphoreFunc							queueSignalSemaphore;
+QueueWaitSemaphoreFunc								queueWaitSemaphore;
+CreateEventFunc										createEvent;
+DestroyEventFunc									destroyEvent;
+GetEventStatusFunc									getEventStatus;
+SetEventFunc										setEvent;
+ResetEventFunc										resetEvent;
+CreateQueryPoolFunc									createQueryPool;
+DestroyQueryPoolFunc								destroyQueryPool;
+GetQueryPoolResultsFunc								getQueryPoolResults;
+CreateBufferFunc									createBuffer;
+DestroyBufferFunc									destroyBuffer;
+CreateBufferViewFunc								createBufferView;
+DestroyBufferViewFunc								destroyBufferView;
+CreateImageFunc										createImage;
+DestroyImageFunc									destroyImage;
+GetImageSubresourceLayoutFunc						getImageSubresourceLayout;
+CreateImageViewFunc									createImageView;
+DestroyImageViewFunc								destroyImageView;
+CreateShaderModuleFunc								createShaderModule;
+DestroyShaderModuleFunc								destroyShaderModule;
+CreateShaderFunc									createShader;
+DestroyShaderFunc									destroyShader;
+CreatePipelineCacheFunc								createPipelineCache;
+DestroyPipelineCacheFunc							destroyPipelineCache;
+GetPipelineCacheSizeFunc							getPipelineCacheSize;
+GetPipelineCacheDataFunc							getPipelineCacheData;
+MergePipelineCachesFunc								mergePipelineCaches;
+CreateGraphicsPipelinesFunc							createGraphicsPipelines;
+CreateComputePipelinesFunc							createComputePipelines;
+DestroyPipelineFunc									destroyPipeline;
+CreatePipelineLayoutFunc							createPipelineLayout;
+DestroyPipelineLayoutFunc							destroyPipelineLayout;
+CreateSamplerFunc									createSampler;
+DestroySamplerFunc									destroySampler;
+CreateDescriptorSetLayoutFunc						createDescriptorSetLayout;
+DestroyDescriptorSetLayoutFunc						destroyDescriptorSetLayout;
+CreateDescriptorPoolFunc							createDescriptorPool;
+DestroyDescriptorPoolFunc							destroyDescriptorPool;
+ResetDescriptorPoolFunc								resetDescriptorPool;
+AllocDescriptorSetsFunc								allocDescriptorSets;
+FreeDescriptorSetsFunc								freeDescriptorSets;
+UpdateDescriptorSetsFunc							updateDescriptorSets;
+CreateFramebufferFunc								createFramebuffer;
+DestroyFramebufferFunc								destroyFramebuffer;
+CreateRenderPassFunc								createRenderPass;
+DestroyRenderPassFunc								destroyRenderPass;
+GetRenderAreaGranularityFunc						getRenderAreaGranularity;
+CreateCommandPoolFunc								createCommandPool;
+DestroyCommandPoolFunc								destroyCommandPool;
+ResetCommandPoolFunc								resetCommandPool;
+CreateCommandBufferFunc								createCommandBuffer;
+DestroyCommandBufferFunc							destroyCommandBuffer;
+BeginCommandBufferFunc								beginCommandBuffer;
+EndCommandBufferFunc								endCommandBuffer;
+ResetCommandBufferFunc								resetCommandBuffer;
+CmdBindPipelineFunc									cmdBindPipeline;
+CmdSetViewportFunc									cmdSetViewport;
+CmdSetScissorFunc									cmdSetScissor;
+CmdSetLineWidthFunc									cmdSetLineWidth;
+CmdSetDepthBiasFunc									cmdSetDepthBias;
+CmdSetBlendConstantsFunc							cmdSetBlendConstants;
+CmdSetDepthBoundsFunc								cmdSetDepthBounds;
+CmdSetStencilCompareMaskFunc						cmdSetStencilCompareMask;
+CmdSetStencilWriteMaskFunc							cmdSetStencilWriteMask;
+CmdSetStencilReferenceFunc							cmdSetStencilReference;
+CmdBindDescriptorSetsFunc							cmdBindDescriptorSets;
+CmdBindIndexBufferFunc								cmdBindIndexBuffer;
+CmdBindVertexBuffersFunc							cmdBindVertexBuffers;
+CmdDrawFunc											cmdDraw;
+CmdDrawIndexedFunc									cmdDrawIndexed;
+CmdDrawIndirectFunc									cmdDrawIndirect;
+CmdDrawIndexedIndirectFunc							cmdDrawIndexedIndirect;
+CmdDispatchFunc										cmdDispatch;
+CmdDispatchIndirectFunc								cmdDispatchIndirect;
+CmdCopyBufferFunc									cmdCopyBuffer;
+CmdCopyImageFunc									cmdCopyImage;
+CmdBlitImageFunc									cmdBlitImage;
+CmdCopyBufferToImageFunc							cmdCopyBufferToImage;
+CmdCopyImageToBufferFunc							cmdCopyImageToBuffer;
+CmdUpdateBufferFunc									cmdUpdateBuffer;
+CmdFillBufferFunc									cmdFillBuffer;
+CmdClearColorImageFunc								cmdClearColorImage;
+CmdClearDepthStencilImageFunc						cmdClearDepthStencilImage;
+CmdClearColorAttachmentFunc							cmdClearColorAttachment;
+CmdClearDepthStencilAttachmentFunc					cmdClearDepthStencilAttachment;
+CmdResolveImageFunc									cmdResolveImage;
+CmdSetEventFunc										cmdSetEvent;
+CmdResetEventFunc									cmdResetEvent;
+CmdWaitEventsFunc									cmdWaitEvents;
+CmdPipelineBarrierFunc								cmdPipelineBarrier;
+CmdBeginQueryFunc									cmdBeginQuery;
+CmdEndQueryFunc										cmdEndQuery;
+CmdResetQueryPoolFunc								cmdResetQueryPool;
+CmdWriteTimestampFunc								cmdWriteTimestamp;
+CmdCopyQueryPoolResultsFunc							cmdCopyQueryPoolResults;
+CmdPushConstantsFunc								cmdPushConstants;
+CmdBeginRenderPassFunc								cmdBeginRenderPass;
+CmdNextSubpassFunc									cmdNextSubpass;
+CmdEndRenderPassFunc								cmdEndRenderPass;
+CmdExecuteCommandsFunc								cmdExecuteCommands;
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
new file mode 100644
index 0000000..0bf7e6c
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
@@ -0,0 +1,90 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Instance and device initialization utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDeviceUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+
+#include "tcuCommandLine.hpp"
+
+#include "qpInfo.h"
+
+#include <vector>
+
+namespace vk
+{
+
+using std::vector;
+
+Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform)
+{
+	const struct VkApplicationInfo		appInfo			=
+	{
+		VK_STRUCTURE_TYPE_APPLICATION_INFO,		//	VkStructureType	sType;
+		DE_NULL,								//	const void*		pNext;
+		"deqp",									//	const char*		pAppName;
+		qpGetReleaseId(),						//	deUint32		appVersion;
+		"deqp",									//	const char*		pEngineName;
+		qpGetReleaseId(),						//	deUint32		engineVersion;
+		VK_API_VERSION							//	deUint32		apiVersion;
+	};
+	const struct VkInstanceCreateInfo	instanceInfo	=
+	{
+		VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,	//	VkStructureType				sType;
+		DE_NULL,								//	const void*					pNext;
+		&appInfo,								//	const VkApplicationInfo*	pAppInfo;
+		DE_NULL,								//	const VkAllocCallbacks*		pAllocCb;
+		0u,										//	deUint32					layerCount;
+		DE_NULL,								//	const char*const*			ppEnabledLayerNames;
+		0u,										//	deUint32					extensionCount;
+		DE_NULL									//	const char*const*			ppEnabledExtensionNames;
+	};
+
+	return createInstance(vkPlatform, &instanceInfo);
+}
+
+VkPhysicalDevice chooseDevice (const InstanceInterface& vkInstance, VkInstance instance, const tcu::CommandLine& cmdLine)
+{
+	const vector<VkPhysicalDevice>	devices	= enumeratePhysicalDevices(vkInstance, instance);
+
+	if (devices.empty())
+		TCU_THROW(NotSupportedError, "No Vulkan devices available");
+
+	if (!de::inBounds(cmdLine.getVKDeviceId(), 1, (int)devices.size()+1))
+		TCU_THROW(InternalError, "Invalid --deqp-vk-device-id");
+
+	return devices[(size_t)(cmdLine.getVKDeviceId()-1)];
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
new file mode 100644
index 0000000..f57d819
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
@@ -0,0 +1,53 @@
+#ifndef _VKDEVICEUTIL_HPP
+#define _VKDEVICEUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Instance and device initialization utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+
+namespace tcu
+{
+class CommandLine;
+}
+
+namespace vk
+{
+
+Move<VkInstance>	createDefaultInstance	(const PlatformInterface& vkPlatform);
+VkPhysicalDevice	chooseDevice			(const InstanceInterface& vkInstance, VkInstance instance, const tcu::CommandLine& cmdLine);
+
+} // vk
+
+#endif // _VKDEVICEUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkFunctionPointerTypes.inl b/external/vulkancts/framework/vulkan/vkFunctionPointerTypes.inl
new file mode 100644
index 0000000..440e2ef
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkFunctionPointerTypes.inl
@@ -0,0 +1,148 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateInstanceFunc)								(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyInstanceFunc)								(VkInstance instance);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EnumeratePhysicalDevicesFunc)						(VkInstance instance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceFeaturesFunc)					(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceFormatPropertiesFunc)			(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceImageFormatPropertiesFunc)		(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDevicePropertiesFunc)					(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceQueueFamilyPropertiesFunc)		(VkPhysicalDevice physicalDevice, deUint32* pCount, VkQueueFamilyProperties* pQueueFamilyProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceMemoryPropertiesFunc)			(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
+typedef VK_APICALL PFN_vkVoidFunction	(VK_APIENTRY* GetInstanceProcAddrFunc)							(VkInstance instance, const char* pName);
+typedef VK_APICALL PFN_vkVoidFunction	(VK_APIENTRY* GetDeviceProcAddrFunc)							(VkDevice device, const char* pName);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateDeviceFunc)									(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyDeviceFunc)								(VkDevice device);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EnumerateInstanceExtensionPropertiesFunc)			(const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EnumerateDeviceExtensionPropertiesFunc)			(VkPhysicalDevice physicalDevice, const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EnumerateInstanceLayerPropertiesFunc)				(deUint32* pCount, VkLayerProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EnumerateDeviceLayerPropertiesFunc)				(VkPhysicalDevice physicalDevice, deUint32* pCount, VkLayerProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetDeviceQueueFunc)								(VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex, VkQueue* pQueue);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueSubmitFunc)									(VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueWaitIdleFunc)								(VkQueue queue);
+typedef VK_APICALL VkResult				(VK_APIENTRY* DeviceWaitIdleFunc)								(VkDevice device);
+typedef VK_APICALL VkResult				(VK_APIENTRY* AllocMemoryFunc)									(VkDevice device, const VkMemoryAllocInfo* pAllocInfo, VkDeviceMemory* pMem);
+typedef VK_APICALL void					(VK_APIENTRY* FreeMemoryFunc)									(VkDevice device, VkDeviceMemory mem);
+typedef VK_APICALL VkResult				(VK_APIENTRY* MapMemoryFunc)									(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData);
+typedef VK_APICALL void					(VK_APIENTRY* UnmapMemoryFunc)									(VkDevice device, VkDeviceMemory mem);
+typedef VK_APICALL VkResult				(VK_APIENTRY* FlushMappedMemoryRangesFunc)						(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges);
+typedef VK_APICALL VkResult				(VK_APIENTRY* InvalidateMappedMemoryRangesFunc)					(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetDeviceMemoryCommitmentFunc)					(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes);
+typedef VK_APICALL VkResult				(VK_APIENTRY* BindBufferMemoryFunc)								(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset);
+typedef VK_APICALL VkResult				(VK_APIENTRY* BindImageMemoryFunc)								(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetBufferMemoryRequirementsFunc)					(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetImageMemoryRequirementsFunc)					(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetImageSparseMemoryRequirementsFunc)				(VkDevice device, VkImage image, deUint32* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPhysicalDeviceSparseImageFormatPropertiesFunc)	(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, deUint32 samples, VkImageUsageFlags usage, VkImageTiling tiling, deUint32* pNumProperties, VkSparseImageFormatProperties* pProperties);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueBindSparseBufferMemoryFunc)					(VkQueue queue, VkBuffer buffer, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueBindSparseImageOpaqueMemoryFunc)				(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueBindSparseImageMemoryFunc)					(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseImageMemoryBindInfo* pBindInfo);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateFenceFunc)									(VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyFenceFunc)									(VkDevice device, VkFence fence);
+typedef VK_APICALL VkResult				(VK_APIENTRY* ResetFencesFunc)									(VkDevice device, deUint32 fenceCount, const VkFence* pFences);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetFenceStatusFunc)								(VkDevice device, VkFence fence);
+typedef VK_APICALL VkResult				(VK_APIENTRY* WaitForFencesFunc)								(VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateSemaphoreFunc)								(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore);
+typedef VK_APICALL void					(VK_APIENTRY* DestroySemaphoreFunc)								(VkDevice device, VkSemaphore semaphore);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueSignalSemaphoreFunc)							(VkQueue queue, VkSemaphore semaphore);
+typedef VK_APICALL VkResult				(VK_APIENTRY* QueueWaitSemaphoreFunc)							(VkQueue queue, VkSemaphore semaphore);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateEventFunc)									(VkDevice device, const VkEventCreateInfo* pCreateInfo, VkEvent* pEvent);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyEventFunc)									(VkDevice device, VkEvent event);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetEventStatusFunc)								(VkDevice device, VkEvent event);
+typedef VK_APICALL VkResult				(VK_APIENTRY* SetEventFunc)										(VkDevice device, VkEvent event);
+typedef VK_APICALL VkResult				(VK_APIENTRY* ResetEventFunc)									(VkDevice device, VkEvent event);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateQueryPoolFunc)								(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, VkQueryPool* pQueryPool);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyQueryPoolFunc)								(VkDevice device, VkQueryPool queryPool);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetQueryPoolResultsFunc)							(VkDevice device, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, deUintptr* pDataSize, void* pData, VkQueryResultFlags flags);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateBufferFunc)									(VkDevice device, const VkBufferCreateInfo* pCreateInfo, VkBuffer* pBuffer);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyBufferFunc)								(VkDevice device, VkBuffer buffer);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateBufferViewFunc)								(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, VkBufferView* pView);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyBufferViewFunc)							(VkDevice device, VkBufferView bufferView);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateImageFunc)									(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyImageFunc)									(VkDevice device, VkImage image);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetImageSubresourceLayoutFunc)					(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateImageViewFunc)								(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyImageViewFunc)								(VkDevice device, VkImageView imageView);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateShaderModuleFunc)							(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyShaderModuleFunc)							(VkDevice device, VkShaderModule shaderModule);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateShaderFunc)									(VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyShaderFunc)								(VkDevice device, VkShader shader);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreatePipelineCacheFunc)							(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyPipelineCacheFunc)							(VkDevice device, VkPipelineCache pipelineCache);
+typedef VK_APICALL deUintptr			(VK_APIENTRY* GetPipelineCacheSizeFunc)							(VkDevice device, VkPipelineCache pipelineCache);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetPipelineCacheDataFunc)							(VkDevice device, VkPipelineCache pipelineCache, void* pData);
+typedef VK_APICALL VkResult				(VK_APIENTRY* MergePipelineCachesFunc)							(VkDevice device, VkPipelineCache destCache, deUint32 srcCacheCount, const VkPipelineCache* pSrcCaches);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateGraphicsPipelinesFunc)						(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateComputePipelinesFunc)						(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyPipelineFunc)								(VkDevice device, VkPipeline pipeline);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreatePipelineLayoutFunc)							(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyPipelineLayoutFunc)						(VkDevice device, VkPipelineLayout pipelineLayout);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateSamplerFunc)								(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler);
+typedef VK_APICALL void					(VK_APIENTRY* DestroySamplerFunc)								(VkDevice device, VkSampler sampler);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateDescriptorSetLayoutFunc)					(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyDescriptorSetLayoutFunc)					(VkDevice device, VkDescriptorSetLayout descriptorSetLayout);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateDescriptorPoolFunc)							(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorPool* pDescriptorPool);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyDescriptorPoolFunc)						(VkDevice device, VkDescriptorPool descriptorPool);
+typedef VK_APICALL VkResult				(VK_APIENTRY* ResetDescriptorPoolFunc)							(VkDevice device, VkDescriptorPool descriptorPool);
+typedef VK_APICALL VkResult				(VK_APIENTRY* AllocDescriptorSetsFunc)							(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, deUint32 count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets);
+typedef VK_APICALL VkResult				(VK_APIENTRY* FreeDescriptorSetsFunc)							(VkDevice device, VkDescriptorPool descriptorPool, deUint32 count, const VkDescriptorSet* pDescriptorSets);
+typedef VK_APICALL void					(VK_APIENTRY* UpdateDescriptorSetsFunc)							(VkDevice device, deUint32 writeCount, const VkWriteDescriptorSet* pDescriptorWrites, deUint32 copyCount, const VkCopyDescriptorSet* pDescriptorCopies);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateFramebufferFunc)							(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, VkFramebuffer* pFramebuffer);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyFramebufferFunc)							(VkDevice device, VkFramebuffer framebuffer);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateRenderPassFunc)								(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyRenderPassFunc)							(VkDevice device, VkRenderPass renderPass);
+typedef VK_APICALL VkResult				(VK_APIENTRY* GetRenderAreaGranularityFunc)						(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateCommandPoolFunc)							(VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo, VkCmdPool* pCmdPool);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyCommandPoolFunc)							(VkDevice device, VkCmdPool cmdPool);
+typedef VK_APICALL VkResult				(VK_APIENTRY* ResetCommandPoolFunc)								(VkDevice device, VkCmdPool cmdPool, VkCmdPoolResetFlags flags);
+typedef VK_APICALL VkResult				(VK_APIENTRY* CreateCommandBufferFunc)							(VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, VkCmdBuffer* pCmdBuffer);
+typedef VK_APICALL void					(VK_APIENTRY* DestroyCommandBufferFunc)							(VkDevice device, VkCmdBuffer commandBuffer);
+typedef VK_APICALL VkResult				(VK_APIENTRY* BeginCommandBufferFunc)							(VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo);
+typedef VK_APICALL VkResult				(VK_APIENTRY* EndCommandBufferFunc)								(VkCmdBuffer cmdBuffer);
+typedef VK_APICALL VkResult				(VK_APIENTRY* ResetCommandBufferFunc)							(VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBindPipelineFunc)								(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetViewportFunc)								(VkCmdBuffer cmdBuffer, deUint32 viewportCount, const VkViewport* pViewports);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetScissorFunc)								(VkCmdBuffer cmdBuffer, deUint32 scissorCount, const VkRect2D* pScissors);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetLineWidthFunc)								(VkCmdBuffer cmdBuffer, float lineWidth);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetDepthBiasFunc)								(VkCmdBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetBlendConstantsFunc)							(VkCmdBuffer cmdBuffer, const float blendConst[4]);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetDepthBoundsFunc)							(VkCmdBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetStencilCompareMaskFunc)						(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilCompareMask);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetStencilWriteMaskFunc)						(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilWriteMask);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetStencilReferenceFunc)						(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilReference);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBindDescriptorSetsFunc)						(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, deUint32 firstSet, deUint32 setCount, const VkDescriptorSet* pDescriptorSets, deUint32 dynamicOffsetCount, const deUint32* pDynamicOffsets);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBindIndexBufferFunc)							(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBindVertexBuffersFunc)							(VkCmdBuffer cmdBuffer, deUint32 startBinding, deUint32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDrawFunc)										(VkCmdBuffer cmdBuffer, deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDrawIndexedFunc)								(VkCmdBuffer cmdBuffer, deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDrawIndirectFunc)								(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDrawIndexedIndirectFunc)						(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDispatchFunc)									(VkCmdBuffer cmdBuffer, deUint32 x, deUint32 y, deUint32 z);
+typedef VK_APICALL void					(VK_APIENTRY* CmdDispatchIndirectFunc)							(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset);
+typedef VK_APICALL void					(VK_APIENTRY* CmdCopyBufferFunc)								(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, deUint32 regionCount, const VkBufferCopy* pRegions);
+typedef VK_APICALL void					(VK_APIENTRY* CmdCopyImageFunc)									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageCopy* pRegions);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBlitImageFunc)									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageBlit* pRegions, VkTexFilter filter);
+typedef VK_APICALL void					(VK_APIENTRY* CmdCopyBufferToImageFunc)							(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkBufferImageCopy* pRegions);
+typedef VK_APICALL void					(VK_APIENTRY* CmdCopyImageToBufferFunc)							(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, deUint32 regionCount, const VkBufferImageCopy* pRegions);
+typedef VK_APICALL void					(VK_APIENTRY* CmdUpdateBufferFunc)								(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const deUint32* pData);
+typedef VK_APICALL void					(VK_APIENTRY* CmdFillBufferFunc)								(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, deUint32 data);
+typedef VK_APICALL void					(VK_APIENTRY* CmdClearColorImageFunc)							(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rangeCount, const VkImageSubresourceRange* pRanges);
+typedef VK_APICALL void					(VK_APIENTRY* CmdClearDepthStencilImageFunc)					(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rangeCount, const VkImageSubresourceRange* pRanges);
+typedef VK_APICALL void					(VK_APIENTRY* CmdClearColorAttachmentFunc)						(VkCmdBuffer cmdBuffer, deUint32 colorAttachment, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rectCount, const VkRect3D* pRects);
+typedef VK_APICALL void					(VK_APIENTRY* CmdClearDepthStencilAttachmentFunc)				(VkCmdBuffer cmdBuffer, VkImageAspectFlags aspectMask, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rectCount, const VkRect3D* pRects);
+typedef VK_APICALL void					(VK_APIENTRY* CmdResolveImageFunc)								(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageResolve* pRegions);
+typedef VK_APICALL void					(VK_APIENTRY* CmdSetEventFunc)									(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+typedef VK_APICALL void					(VK_APIENTRY* CmdResetEventFunc)								(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+typedef VK_APICALL void					(VK_APIENTRY* CmdWaitEventsFunc)								(VkCmdBuffer cmdBuffer, deUint32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, deUint32 memBarrierCount, const void* const* ppMemBarriers);
+typedef VK_APICALL void					(VK_APIENTRY* CmdPipelineBarrierFunc)							(VkCmdBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, VkBool32 byRegion, deUint32 memBarrierCount, const void* const* ppMemBarriers);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBeginQueryFunc)								(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot, VkQueryControlFlags flags);
+typedef VK_APICALL void					(VK_APIENTRY* CmdEndQueryFunc)									(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot);
+typedef VK_APICALL void					(VK_APIENTRY* CmdResetQueryPoolFunc)							(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount);
+typedef VK_APICALL void					(VK_APIENTRY* CmdWriteTimestampFunc)							(VkCmdBuffer cmdBuffer, VkTimestampType timestampType, VkBuffer destBuffer, VkDeviceSize destOffset);
+typedef VK_APICALL void					(VK_APIENTRY* CmdCopyQueryPoolResultsFunc)						(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags);
+typedef VK_APICALL void					(VK_APIENTRY* CmdPushConstantsFunc)								(VkCmdBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, deUint32 start, deUint32 length, const void* values);
+typedef VK_APICALL void					(VK_APIENTRY* CmdBeginRenderPassFunc)							(VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents);
+typedef VK_APICALL void					(VK_APIENTRY* CmdNextSubpassFunc)								(VkCmdBuffer cmdBuffer, VkRenderPassContents contents);
+typedef VK_APICALL void					(VK_APIENTRY* CmdEndRenderPassFunc)								(VkCmdBuffer cmdBuffer);
+typedef VK_APICALL void					(VK_APIENTRY* CmdExecuteCommandsFunc)							(VkCmdBuffer cmdBuffer, deUint32 cmdBuffersCount, const VkCmdBuffer* pCmdBuffers);
diff --git a/external/vulkancts/framework/vulkan/vkGlslToSpirV.cpp b/external/vulkancts/framework/vulkan/vkGlslToSpirV.cpp
new file mode 100644
index 0000000..9c9c12e
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkGlslToSpirV.cpp
@@ -0,0 +1,316 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief GLSL to SPIR-V.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkGlslToSpirV.hpp"
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+#include "deClock.h"
+#include "qpDebugOut.h"
+
+#if defined(DEQP_HAVE_GLSLANG)
+#	include "deSingleton.h"
+#	include "deMutex.hpp"
+
+#	include "SPIRV/GlslangToSpv.h"
+#	include "SPIRV/disassemble.h"
+#	include "SPIRV/doc.h"
+#	include "glslang/Include/InfoSink.h"
+#	include "glslang/Include/ShHandle.h"
+#	include "glslang/MachineIndependent/localintermediate.h"
+#	include "glslang/Public/ShaderLang.h"
+
+#endif
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+
+#if defined(DEQP_HAVE_GLSLANG)
+
+namespace
+{
+
+EShLanguage getGlslangStage (glu::ShaderType type)
+{
+	static const EShLanguage stageMap[] =
+	{
+		EShLangVertex,
+		EShLangFragment,
+		EShLangGeometry,
+		EShLangTessControl,
+		EShLangTessEvaluation,
+		EShLangCompute,
+	};
+	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
+}
+
+static volatile deSingletonState	s_glslangInitState	= DE_SINGLETON_STATE_NOT_INITIALIZED;
+static de::Mutex					s_glslangLock;
+
+void initGlslang (void*)
+{
+	// Main compiler
+	ShInitialize();
+
+	// SPIR-V disassembly
+	spv::Parameterize();
+}
+
+void prepareGlslang (void)
+{
+	deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
+}
+
+class SpvGenerator : public TCompiler
+{
+public:
+	SpvGenerator (EShLanguage language, std::vector<deUint32>& dst, TInfoSink& infoSink)
+		: TCompiler	(language, infoSink)
+		, m_dst		(dst)
+	{
+	}
+
+	bool compile (TIntermNode* root, int version = 0, EProfile profile = ENoProfile)
+	{
+		glslang::TIntermediate intermediate(getLanguage(), version, profile);
+		intermediate.setTreeRoot(root);
+		intermediate.finalCheck(getInfoSink());
+		glslang::GlslangToSpv(intermediate, m_dst);
+		return true;
+	}
+
+private:
+	std::vector<deUint32>&	m_dst;
+};
+
+// \todo [2015-06-19 pyry] Specialize these per GLSL version
+
+// Fail compilation if more members are added to TLimits or TBuiltInResource
+struct LimitsSizeHelper_s			{ bool m0, m1, m2, m3, m4, m5, m6, m7, m8; };
+struct BuiltInResourceSizeHelper_s	{ int m[83]; LimitsSizeHelper_s l; };
+
+DE_STATIC_ASSERT(sizeof(TLimits)			== sizeof(LimitsSizeHelper_s));
+DE_STATIC_ASSERT(sizeof(TBuiltInResource)	== sizeof(BuiltInResourceSizeHelper_s));
+
+void getDefaultLimits (TLimits* limits)
+{
+	limits->nonInductiveForLoops					= true;
+	limits->whileLoops								= true;
+	limits->doWhileLoops							= true;
+	limits->generalUniformIndexing					= true;
+	limits->generalAttributeMatrixVectorIndexing	= true;
+	limits->generalVaryingIndexing					= true;
+	limits->generalSamplerIndexing					= true;
+	limits->generalVariableIndexing					= true;
+	limits->generalConstantMatrixVectorIndexing		= true;
+}
+
+void getDefaultBuiltInResources (TBuiltInResource* builtin)
+{
+	getDefaultLimits(&builtin->limits);
+
+	builtin->maxLights									= 32;
+	builtin->maxClipPlanes								= 6;
+	builtin->maxTextureUnits							= 32;
+	builtin->maxTextureCoords							= 32;
+	builtin->maxVertexAttribs							= 64;
+	builtin->maxVertexUniformComponents					= 4096;
+	builtin->maxVaryingFloats							= 64;
+	builtin->maxVertexTextureImageUnits					= 32;
+	builtin->maxCombinedTextureImageUnits				= 80;
+	builtin->maxTextureImageUnits						= 32;
+	builtin->maxFragmentUniformComponents				= 4096;
+	builtin->maxDrawBuffers								= 32;
+	builtin->maxVertexUniformVectors					= 128;
+	builtin->maxVaryingVectors							= 8;
+	builtin->maxFragmentUniformVectors					= 16;
+	builtin->maxVertexOutputVectors						= 16;
+	builtin->maxFragmentInputVectors					= 15;
+	builtin->minProgramTexelOffset						= -8;
+	builtin->maxProgramTexelOffset						= 7;
+	builtin->maxClipDistances							= 8;
+	builtin->maxComputeWorkGroupCountX					= 65535;
+	builtin->maxComputeWorkGroupCountY					= 65535;
+	builtin->maxComputeWorkGroupCountZ					= 65535;
+	builtin->maxComputeWorkGroupSizeX					= 1024;
+	builtin->maxComputeWorkGroupSizeX					= 1024;
+	builtin->maxComputeWorkGroupSizeZ					= 64;
+	builtin->maxComputeUniformComponents				= 1024;
+	builtin->maxComputeTextureImageUnits				= 16;
+	builtin->maxComputeImageUniforms					= 8;
+	builtin->maxComputeAtomicCounters					= 8;
+	builtin->maxComputeAtomicCounterBuffers				= 1;
+	builtin->maxVaryingComponents						= 60;
+	builtin->maxVertexOutputComponents					= 64;
+	builtin->maxGeometryInputComponents					= 64;
+	builtin->maxGeometryOutputComponents				= 128;
+	builtin->maxFragmentInputComponents					= 128;
+	builtin->maxImageUnits								= 8;
+	builtin->maxCombinedImageUnitsAndFragmentOutputs	= 8;
+	builtin->maxCombinedShaderOutputResources			= 8;
+	builtin->maxImageSamples							= 0;
+	builtin->maxVertexImageUniforms						= 0;
+	builtin->maxTessControlImageUniforms				= 0;
+	builtin->maxTessEvaluationImageUniforms				= 0;
+	builtin->maxGeometryImageUniforms					= 0;
+	builtin->maxFragmentImageUniforms					= 8;
+	builtin->maxCombinedImageUniforms					= 8;
+	builtin->maxGeometryTextureImageUnits				= 16;
+	builtin->maxGeometryOutputVertices					= 256;
+	builtin->maxGeometryTotalOutputComponents			= 1024;
+	builtin->maxGeometryUniformComponents				= 1024;
+	builtin->maxGeometryVaryingComponents				= 64;
+	builtin->maxTessControlInputComponents				= 128;
+	builtin->maxTessControlOutputComponents				= 128;
+	builtin->maxTessControlTextureImageUnits			= 16;
+	builtin->maxTessControlUniformComponents			= 1024;
+	builtin->maxTessControlTotalOutputComponents		= 4096;
+	builtin->maxTessEvaluationInputComponents			= 128;
+	builtin->maxTessEvaluationOutputComponents			= 128;
+	builtin->maxTessEvaluationTextureImageUnits			= 16;
+	builtin->maxTessEvaluationUniformComponents			= 1024;
+	builtin->maxTessPatchComponents						= 120;
+	builtin->maxPatchVertices							= 32;
+	builtin->maxTessGenLevel							= 64;
+	builtin->maxViewports								= 16;
+	builtin->maxVertexAtomicCounters					= 0;
+	builtin->maxTessControlAtomicCounters				= 0;
+	builtin->maxTessEvaluationAtomicCounters			= 0;
+	builtin->maxGeometryAtomicCounters					= 0;
+	builtin->maxFragmentAtomicCounters					= 8;
+	builtin->maxCombinedAtomicCounters					= 8;
+	builtin->maxAtomicCounterBindings					= 1;
+	builtin->maxVertexAtomicCounterBuffers				= 0;
+	builtin->maxTessControlAtomicCounterBuffers			= 0;
+	builtin->maxTessEvaluationAtomicCounterBuffers		= 0;
+	builtin->maxGeometryAtomicCounterBuffers			= 0;
+	builtin->maxFragmentAtomicCounterBuffers			= 1;
+	builtin->maxCombinedAtomicCounterBuffers			= 1;
+	builtin->maxAtomicCounterBufferSize					= 16384;
+	builtin->maxTransformFeedbackBuffers				= 4;
+	builtin->maxTransformFeedbackInterleavedComponents	= 64;
+	builtin->maxCullDistances							= 8;
+	builtin->maxCombinedClipAndCullDistances			= 8;
+	builtin->maxSamples									= 4;
+};
+
+} // anonymous
+
+void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo)
+{
+	TBuiltInResource	builtinRes;
+
+	prepareGlslang();
+	getDefaultBuiltInResources(&builtinRes);
+
+	// \note Compiles only first found shader
+	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+	{
+		if (!program.sources[shaderType].empty())
+		{
+			de::ScopedLock		compileLock			(s_glslangLock);
+			const std::string&	srcText				= program.sources[shaderType][0];
+			const char*			srcPtrs[]			= { srcText.c_str() };
+			int					srcLengths[]		= { (int)srcText.size() };
+			vector<deUint32>	spvBlob;
+			TInfoSink			infoSink;
+			SpvGenerator		compiler			(getGlslangStage(glu::ShaderType(shaderType)), spvBlob, infoSink);
+			const deUint64		compileStartTime	= deGetMicroseconds();
+			const int			compileOk			= ShCompile(static_cast<ShHandle>(&compiler), srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs), srcLengths, EShOptNone, &builtinRes, 0);
+
+			{
+				glu::ShaderInfo	shaderBuildInfo;
+
+				shaderBuildInfo.type			= (glu::ShaderType)shaderType;
+				shaderBuildInfo.source			= srcText;
+				shaderBuildInfo.infoLog			= infoSink.info.c_str(); // \todo [2015-07-13 pyry] Include debug log?
+				shaderBuildInfo.compileTimeUs	= deGetMicroseconds()-compileStartTime;
+				shaderBuildInfo.compileOk		= (compileOk != 0);
+
+				buildInfo->shaders.push_back(shaderBuildInfo);
+			}
+
+			buildInfo->program.infoLog		= "(No linking performed)";
+			buildInfo->program.linkOk		= (compileOk != 0);
+			buildInfo->program.linkTimeUs	= 0;
+
+			if (compileOk == 0)
+				TCU_FAIL("Failed to compile shader");
+
+			dst->resize(spvBlob.size() * sizeof(deUint32));
+#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
+			deMemcpy(&(*dst)[0], &spvBlob[0], dst->size());
+#else
+#	error "Big-endian not supported"
+#endif
+
+			return;
+		}
+	}
+
+	TCU_THROW(InternalError, "Can't compile empty program");
+}
+
+void disassembleSpirV (size_t binarySize, const deUint8* binary, std::ostream* dst)
+{
+	std::vector<deUint32>	binForDisasm	(binarySize/4);
+
+	DE_ASSERT(binarySize%4 == 0);
+
+#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
+	deMemcpy(&binForDisasm[0], binary, binarySize);
+#else
+#	error "Big-endian not supported"
+#endif
+
+	spv::Disassemble(*dst, binForDisasm);
+}
+
+#else // defined(DEQP_HAVE_GLSLANG)
+
+void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>*, glu::ShaderProgramInfo*)
+{
+	TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
+}
+
+void disassembleSpirV (size_t, const deUint8*, std::ostream*)
+{
+	TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_GLSLANG not defined)");
+}
+
+#endif
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkGlslToSpirV.hpp b/external/vulkancts/framework/vulkan/vkGlslToSpirV.hpp
new file mode 100644
index 0000000..df4513b
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkGlslToSpirV.hpp
@@ -0,0 +1,54 @@
+#ifndef _VKGLSLTOSPIRV_HPP
+#define _VKGLSLTOSPIRV_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief GLSL to SPIR-V.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkPrograms.hpp"
+#include "gluShaderProgram.hpp"
+
+#include <ostream>
+
+namespace vk
+{
+
+//! Compile GLSL program to SPIR-V. Will fail with NotSupportedError if compiler is not available.
+void	glslToSpirV			(const glu::ProgramSources& src, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo);
+
+//! Disassemble SPIR-V binary
+void	disassembleSpirV	(size_t binarySize, const deUint8* binary, std::ostream* dst);
+
+} // vk
+
+#endif // _VKGLSLTOSPIRV_HPP
diff --git a/external/vulkancts/framework/vulkan/vkHandleType.inl b/external/vulkancts/framework/vulkan/vkHandleType.inl
new file mode 100644
index 0000000..374f979
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkHandleType.inl
@@ -0,0 +1,34 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+enum HandleType
+{
+	HANDLE_TYPE_INSTANCE = 0,
+	HANDLE_TYPE_PHYSICAL_DEVICE,
+	HANDLE_TYPE_DEVICE,
+	HANDLE_TYPE_QUEUE,
+	HANDLE_TYPE_CMD_BUFFER,
+	HANDLE_TYPE_FENCE,
+	HANDLE_TYPE_DEVICE_MEMORY,
+	HANDLE_TYPE_BUFFER,
+	HANDLE_TYPE_IMAGE,
+	HANDLE_TYPE_SEMAPHORE,
+	HANDLE_TYPE_EVENT,
+	HANDLE_TYPE_QUERY_POOL,
+	HANDLE_TYPE_BUFFER_VIEW,
+	HANDLE_TYPE_IMAGE_VIEW,
+	HANDLE_TYPE_SHADER_MODULE,
+	HANDLE_TYPE_SHADER,
+	HANDLE_TYPE_PIPELINE_CACHE,
+	HANDLE_TYPE_PIPELINE_LAYOUT,
+	HANDLE_TYPE_RENDER_PASS,
+	HANDLE_TYPE_PIPELINE,
+	HANDLE_TYPE_DESCRIPTOR_SET_LAYOUT,
+	HANDLE_TYPE_SAMPLER,
+	HANDLE_TYPE_DESCRIPTOR_POOL,
+	HANDLE_TYPE_DESCRIPTOR_SET,
+	HANDLE_TYPE_FRAMEBUFFER,
+	HANDLE_TYPE_CMD_POOL,
+	HANDLE_TYPE_LAST
+};
+
diff --git a/external/vulkancts/framework/vulkan/vkImageUtil.cpp b/external/vulkancts/framework/vulkan/vkImageUtil.cpp
new file mode 100644
index 0000000..70e93f7
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkImageUtil.cpp
@@ -0,0 +1,629 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for images.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkImageUtil.hpp"
+#include "tcuTextureUtil.hpp"
+
+namespace vk
+{
+
+bool isFloatFormat (VkFormat format)
+{
+	return tcu::getTextureChannelClass(mapVkFormat(format).type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
+}
+
+bool isUnormFormat (VkFormat format)
+{
+	return tcu::getTextureChannelClass(mapVkFormat(format).type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
+}
+
+bool isSnormFormat (VkFormat format)
+{
+	return tcu::getTextureChannelClass(mapVkFormat(format).type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT;
+}
+
+bool isIntFormat (VkFormat format)
+{
+	return tcu::getTextureChannelClass(mapVkFormat(format).type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
+}
+
+bool isUintFormat (VkFormat format)
+{
+	return tcu::getTextureChannelClass(mapVkFormat(format).type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
+}
+
+bool isDepthStencilFormat (VkFormat format)
+{
+	if (isCompressedFormat(format))
+		return false;
+
+	const tcu::TextureFormat tcuFormat = mapVkFormat(format);
+	return tcuFormat.order == tcu::TextureFormat::D || tcuFormat.order == tcu::TextureFormat::S || tcuFormat.order == tcu::TextureFormat::DS;
+}
+
+bool isCompressedFormat (VkFormat format)
+{
+	// update this mapping if VkFormat changes
+	DE_STATIC_ASSERT(VK_FORMAT_LAST == 174);
+
+	switch (format)
+	{
+		case VK_FORMAT_BC1_RGB_UNORM:
+		case VK_FORMAT_BC1_RGB_SRGB:
+		case VK_FORMAT_BC1_RGBA_UNORM:
+		case VK_FORMAT_BC1_RGBA_SRGB:
+		case VK_FORMAT_BC2_UNORM:
+		case VK_FORMAT_BC2_SRGB:
+		case VK_FORMAT_BC3_UNORM:
+		case VK_FORMAT_BC3_SRGB:
+		case VK_FORMAT_BC4_UNORM:
+		case VK_FORMAT_BC4_SNORM:
+		case VK_FORMAT_BC5_UNORM:
+		case VK_FORMAT_BC5_SNORM:
+		case VK_FORMAT_BC6H_UFLOAT:
+		case VK_FORMAT_BC6H_SFLOAT:
+		case VK_FORMAT_BC7_UNORM:
+		case VK_FORMAT_BC7_SRGB:
+		case VK_FORMAT_ETC2_R8G8B8_UNORM:
+		case VK_FORMAT_ETC2_R8G8B8_SRGB:
+		case VK_FORMAT_ETC2_R8G8B8A1_UNORM:
+		case VK_FORMAT_ETC2_R8G8B8A1_SRGB:
+		case VK_FORMAT_ETC2_R8G8B8A8_UNORM:
+		case VK_FORMAT_ETC2_R8G8B8A8_SRGB:
+		case VK_FORMAT_EAC_R11_UNORM:
+		case VK_FORMAT_EAC_R11_SNORM:
+		case VK_FORMAT_EAC_R11G11_UNORM:
+		case VK_FORMAT_EAC_R11G11_SNORM:
+		case VK_FORMAT_ASTC_4x4_UNORM:
+		case VK_FORMAT_ASTC_4x4_SRGB:
+		case VK_FORMAT_ASTC_5x4_UNORM:
+		case VK_FORMAT_ASTC_5x4_SRGB:
+		case VK_FORMAT_ASTC_5x5_UNORM:
+		case VK_FORMAT_ASTC_5x5_SRGB:
+		case VK_FORMAT_ASTC_6x5_UNORM:
+		case VK_FORMAT_ASTC_6x5_SRGB:
+		case VK_FORMAT_ASTC_6x6_UNORM:
+		case VK_FORMAT_ASTC_6x6_SRGB:
+		case VK_FORMAT_ASTC_8x5_UNORM:
+		case VK_FORMAT_ASTC_8x5_SRGB:
+		case VK_FORMAT_ASTC_8x6_UNORM:
+		case VK_FORMAT_ASTC_8x6_SRGB:
+		case VK_FORMAT_ASTC_8x8_UNORM:
+		case VK_FORMAT_ASTC_8x8_SRGB:
+		case VK_FORMAT_ASTC_10x5_UNORM:
+		case VK_FORMAT_ASTC_10x5_SRGB:
+		case VK_FORMAT_ASTC_10x6_UNORM:
+		case VK_FORMAT_ASTC_10x6_SRGB:
+		case VK_FORMAT_ASTC_10x8_UNORM:
+		case VK_FORMAT_ASTC_10x8_SRGB:
+		case VK_FORMAT_ASTC_10x10_UNORM:
+		case VK_FORMAT_ASTC_10x10_SRGB:
+		case VK_FORMAT_ASTC_12x10_UNORM:
+		case VK_FORMAT_ASTC_12x10_SRGB:
+		case VK_FORMAT_ASTC_12x12_UNORM:
+		case VK_FORMAT_ASTC_12x12_SRGB:
+			return true;
+
+		default:
+			return false;
+	}
+}
+
+VkFormat mapTextureFormat (const tcu::TextureFormat& format)
+{
+	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST < (1<<16));
+	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELTYPE_LAST < (1<<16));
+
+#define PACK_FMT(ORDER, TYPE) ((int(ORDER) << 16) | int(TYPE))
+#define FMT_CASE(ORDER, TYPE) PACK_FMT(tcu::TextureFormat::ORDER, tcu::TextureFormat::TYPE)
+
+	// update this mapping if VkFormat changes
+	DE_STATIC_ASSERT(VK_FORMAT_LAST == 174);
+
+	switch (PACK_FMT(format.order, format.type))
+	{
+		case FMT_CASE(RG, UNORM_BYTE_44):					return VK_FORMAT_R4G4_UNORM;
+		case FMT_CASE(RGB, UNORM_SHORT_565):				return VK_FORMAT_R5G6B5_UNORM;
+		case FMT_CASE(RGBA, UNORM_SHORT_4444):				return VK_FORMAT_R4G4B4A4_UNORM;
+		case FMT_CASE(RGBA, UNORM_SHORT_5551):				return VK_FORMAT_R5G5B5A1_UNORM;
+
+		case FMT_CASE(RG, UNSIGNED_BYTE_44):				return VK_FORMAT_R4G4_USCALED;
+		case FMT_CASE(RGBA, UNSIGNED_SHORT_4444):			return VK_FORMAT_R4G4B4A4_USCALED;
+		case FMT_CASE(RGB, UNSIGNED_SHORT_565):				return VK_FORMAT_R5G6B5_USCALED;
+		case FMT_CASE(RGBA, UNSIGNED_SHORT_5551):			return VK_FORMAT_R5G5B5A1_USCALED;
+
+		case FMT_CASE(BGR, UNORM_SHORT_565):				return VK_FORMAT_B5G6R5_UNORM;
+		case FMT_CASE(BGRA, UNORM_SHORT_4444):				return VK_FORMAT_B4G4R4A4_UNORM;
+		case FMT_CASE(BGRA, UNORM_SHORT_5551):				return VK_FORMAT_B5G5R5A1_UNORM;
+
+		case FMT_CASE(BGR, UNSIGNED_SHORT_565):				return VK_FORMAT_B5G6R5_USCALED;
+
+		case FMT_CASE(R, UNORM_INT8):						return VK_FORMAT_R8_UNORM;
+		case FMT_CASE(R, SNORM_INT8):						return VK_FORMAT_R8_SNORM;
+		case FMT_CASE(R, UNSIGNED_INT8):					return VK_FORMAT_R8_UINT;
+		case FMT_CASE(R, SIGNED_INT8):						return VK_FORMAT_R8_SINT;
+		case FMT_CASE(sR, UNORM_INT8):						return VK_FORMAT_R8_SRGB;
+
+		case FMT_CASE(RG, UNORM_INT8):						return VK_FORMAT_R8G8_UNORM;
+		case FMT_CASE(RG, SNORM_INT8):						return VK_FORMAT_R8G8_SNORM;
+		case FMT_CASE(RG, UNSIGNED_INT8):					return VK_FORMAT_R8G8_UINT;
+		case FMT_CASE(RG, SIGNED_INT8):						return VK_FORMAT_R8G8_SINT;
+		case FMT_CASE(sRG, UNORM_INT8):						return VK_FORMAT_R8G8_SRGB;
+
+		case FMT_CASE(RGB, UNORM_INT8):						return VK_FORMAT_R8G8B8_UNORM;
+		case FMT_CASE(RGB, SNORM_INT8):						return VK_FORMAT_R8G8B8_SNORM;
+		case FMT_CASE(RGB, UNSIGNED_INT8):					return VK_FORMAT_R8G8B8_UINT;
+		case FMT_CASE(RGB, SIGNED_INT8):					return VK_FORMAT_R8G8B8_SINT;
+		case FMT_CASE(sRGB, UNORM_INT8):					return VK_FORMAT_R8G8B8_SRGB;
+
+		case FMT_CASE(RGBA, UNORM_INT8):					return VK_FORMAT_R8G8B8A8_UNORM;
+		case FMT_CASE(RGBA, SNORM_INT8):					return VK_FORMAT_R8G8B8A8_SNORM;
+		case FMT_CASE(RGBA, UNSIGNED_INT8):					return VK_FORMAT_R8G8B8A8_UINT;
+		case FMT_CASE(RGBA, SIGNED_INT8):					return VK_FORMAT_R8G8B8A8_SINT;
+		case FMT_CASE(sRGBA, UNORM_INT8):					return VK_FORMAT_R8G8B8A8_SRGB;
+
+		case FMT_CASE(RGBA, SNORM_INT_1010102_REV):			return VK_FORMAT_R10G10B10A2_SNORM;
+		case FMT_CASE(RGBA, UNORM_INT_1010102_REV):			return VK_FORMAT_R10G10B10A2_UNORM;
+		case FMT_CASE(RGBA, UNSIGNED_INT_1010102_REV):		return VK_FORMAT_R10G10B10A2_UINT;
+		case FMT_CASE(RGBA, SIGNED_INT_1010102_REV):		return VK_FORMAT_R10G10B10A2_SINT;
+
+		case FMT_CASE(R, UNORM_INT16):						return VK_FORMAT_R16_UNORM;
+		case FMT_CASE(R, SNORM_INT16):						return VK_FORMAT_R16_SNORM;
+		case FMT_CASE(R, UNSIGNED_INT16):					return VK_FORMAT_R16_UINT;
+		case FMT_CASE(R, SIGNED_INT16):						return VK_FORMAT_R16_SINT;
+		case FMT_CASE(R, HALF_FLOAT):						return VK_FORMAT_R16_SFLOAT;
+
+		case FMT_CASE(RG, UNORM_INT16):						return VK_FORMAT_R16G16_UNORM;
+		case FMT_CASE(RG, SNORM_INT16):						return VK_FORMAT_R16G16_SNORM;
+		case FMT_CASE(RG, UNSIGNED_INT16):					return VK_FORMAT_R16G16_UINT;
+		case FMT_CASE(RG, SIGNED_INT16):					return VK_FORMAT_R16G16_SINT;
+		case FMT_CASE(RG, HALF_FLOAT):						return VK_FORMAT_R16G16_SFLOAT;
+
+		case FMT_CASE(RGB, UNORM_INT16):					return VK_FORMAT_R16G16B16_UNORM;
+		case FMT_CASE(RGB, SNORM_INT16):					return VK_FORMAT_R16G16B16_SNORM;
+		case FMT_CASE(RGB, UNSIGNED_INT16):					return VK_FORMAT_R16G16B16_UINT;
+		case FMT_CASE(RGB, SIGNED_INT16):					return VK_FORMAT_R16G16B16_SINT;
+		case FMT_CASE(RGB, HALF_FLOAT):						return VK_FORMAT_R16G16B16_SFLOAT;
+
+		case FMT_CASE(RGBA, UNORM_INT16):					return VK_FORMAT_R16G16B16A16_UNORM;
+		case FMT_CASE(RGBA, SNORM_INT16):					return VK_FORMAT_R16G16B16A16_SNORM;
+		case FMT_CASE(RGBA, UNSIGNED_INT16):				return VK_FORMAT_R16G16B16A16_UINT;
+		case FMT_CASE(RGBA, SIGNED_INT16):					return VK_FORMAT_R16G16B16A16_SINT;
+		case FMT_CASE(RGBA, HALF_FLOAT):					return VK_FORMAT_R16G16B16A16_SFLOAT;
+
+		case FMT_CASE(R, UNSIGNED_INT32):					return VK_FORMAT_R32_UINT;
+		case FMT_CASE(R, SIGNED_INT32):						return VK_FORMAT_R32_SINT;
+		case FMT_CASE(R, FLOAT):							return VK_FORMAT_R32_SFLOAT;
+
+		case FMT_CASE(RG, UNSIGNED_INT32):					return VK_FORMAT_R32G32_UINT;
+		case FMT_CASE(RG, SIGNED_INT32):					return VK_FORMAT_R32G32_SINT;
+		case FMT_CASE(RG, FLOAT):							return VK_FORMAT_R32G32_SFLOAT;
+
+		case FMT_CASE(RGB, UNSIGNED_INT32):					return VK_FORMAT_R32G32B32_UINT;
+		case FMT_CASE(RGB, SIGNED_INT32):					return VK_FORMAT_R32G32B32_SINT;
+		case FMT_CASE(RGB, FLOAT):							return VK_FORMAT_R32G32B32_SFLOAT;
+
+		case FMT_CASE(RGBA, UNSIGNED_INT32):				return VK_FORMAT_R32G32B32A32_UINT;
+		case FMT_CASE(RGBA, SIGNED_INT32):					return VK_FORMAT_R32G32B32A32_SINT;
+		case FMT_CASE(RGBA, FLOAT):							return VK_FORMAT_R32G32B32A32_SFLOAT;
+
+		case FMT_CASE(R, FLOAT64):							return VK_FORMAT_R64_SFLOAT;
+		case FMT_CASE(RG, FLOAT64):							return VK_FORMAT_R64G64_SFLOAT;
+		case FMT_CASE(RGB, FLOAT64):						return VK_FORMAT_R64G64B64_SFLOAT;
+		case FMT_CASE(RGBA, FLOAT64):						return VK_FORMAT_R64G64B64A64_SFLOAT;
+
+		case FMT_CASE(RGB, UNSIGNED_INT_11F_11F_10F_REV):	return VK_FORMAT_R11G11B10_UFLOAT;
+		case FMT_CASE(RGB, UNSIGNED_INT_999_E5_REV):		return VK_FORMAT_R9G9B9E5_UFLOAT;
+
+		case FMT_CASE(BGR, UNORM_INT8):						return VK_FORMAT_B8G8R8_UNORM;
+		case FMT_CASE(BGR, SNORM_INT8):						return VK_FORMAT_B8G8R8_SNORM;
+		case FMT_CASE(BGR, UNSIGNED_INT8):					return VK_FORMAT_B8G8R8_UINT;
+		case FMT_CASE(BGR, SIGNED_INT8):					return VK_FORMAT_B8G8R8_SINT;
+		case FMT_CASE(sBGR, UNORM_INT8):					return VK_FORMAT_B8G8R8_SRGB;
+
+		case FMT_CASE(BGRA, UNORM_INT8):					return VK_FORMAT_B8G8R8A8_UNORM;
+		case FMT_CASE(BGRA, SNORM_INT8):					return VK_FORMAT_B8G8R8A8_SNORM;
+		case FMT_CASE(BGRA, UNSIGNED_INT8):					return VK_FORMAT_B8G8R8A8_UINT;
+		case FMT_CASE(BGRA, SIGNED_INT8):					return VK_FORMAT_B8G8R8A8_SINT;
+		case FMT_CASE(sBGRA, UNORM_INT8):					return VK_FORMAT_B8G8R8A8_SRGB;
+
+		case FMT_CASE(BGRA, UNORM_INT_1010102_REV):			return VK_FORMAT_B10G10R10A2_UNORM;
+		case FMT_CASE(BGRA, SNORM_INT_1010102_REV):			return VK_FORMAT_B10G10R10A2_SNORM;
+		case FMT_CASE(BGRA, UNSIGNED_INT_1010102_REV):		return VK_FORMAT_B10G10R10A2_UINT;
+		case FMT_CASE(BGRA, SIGNED_INT_1010102_REV):		return VK_FORMAT_B10G10R10A2_SINT;
+
+		case FMT_CASE(D, UNORM_INT16):						return VK_FORMAT_D16_UNORM;
+		case FMT_CASE(D, UNSIGNED_INT_24_8_REV):			return VK_FORMAT_D24_UNORM_X8;
+		case FMT_CASE(D, FLOAT):							return VK_FORMAT_D32_SFLOAT;
+
+		case FMT_CASE(S, UNSIGNED_INT8):					return VK_FORMAT_S8_UINT;
+
+		case FMT_CASE(DS, UNSIGNED_INT_16_8_8):				return VK_FORMAT_D16_UNORM_S8_UINT;
+		case FMT_CASE(DS, UNSIGNED_INT_24_8_REV):			return VK_FORMAT_D24_UNORM_S8_UINT;
+		case FMT_CASE(DS, FLOAT_UNSIGNED_INT_24_8_REV):		return VK_FORMAT_D32_SFLOAT_S8_UINT;
+
+		default:
+			TCU_THROW(InternalError, "Unknown texture format");
+	}
+
+#undef PACK_FMT
+#undef FMT_CASE
+}
+
+tcu::TextureFormat mapVkFormat (VkFormat format)
+{
+	using tcu::TextureFormat;
+
+	// update this mapping if VkFormat changes
+	DE_STATIC_ASSERT(VK_FORMAT_LAST == 174);
+
+	switch (format)
+	{
+		case VK_FORMAT_R4G4_UNORM:			return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_BYTE_44);
+		case VK_FORMAT_R5G6B5_UNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_SHORT_565);
+		case VK_FORMAT_R4G4B4A4_UNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_4444);
+		case VK_FORMAT_R5G5B5A1_UNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_5551);
+
+		case VK_FORMAT_R4G4_USCALED:		return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_BYTE_44);
+		case VK_FORMAT_R4G4B4A4_USCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_SHORT_4444);
+		case VK_FORMAT_R5G6B5_USCALED:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_SHORT_565);
+		case VK_FORMAT_R5G5B5A1_USCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_SHORT_5551);
+
+		case VK_FORMAT_B5G6R5_UNORM:		return TextureFormat(TextureFormat::BGR,	TextureFormat::UNORM_SHORT_565);
+		case VK_FORMAT_B4G4R4A4_UNORM:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNORM_SHORT_4444);
+		case VK_FORMAT_B5G5R5A1_UNORM:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNORM_SHORT_5551);
+
+		case VK_FORMAT_B5G6R5_USCALED:		return TextureFormat(TextureFormat::BGR,	TextureFormat::UNSIGNED_SHORT_565);
+
+		case VK_FORMAT_R8_UNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::UNORM_INT8);
+		case VK_FORMAT_R8_SNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::SNORM_INT8);
+		case VK_FORMAT_R8_USCALED:			return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8_SSCALED:			return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8_UINT:				return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8_SINT:				return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8_SRGB:				return TextureFormat(TextureFormat::sR,		TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_R8G8_UNORM:			return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_INT8);
+		case VK_FORMAT_R8G8_SNORM:			return TextureFormat(TextureFormat::RG,		TextureFormat::SNORM_INT8);
+		case VK_FORMAT_R8G8_USCALED:		return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8_SSCALED:		return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8_UINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8_SINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8_SRGB:			return TextureFormat(TextureFormat::sRG,	TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_R8G8B8_UNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
+		case VK_FORMAT_R8G8B8_SNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SNORM_INT8);
+		case VK_FORMAT_R8G8B8_USCALED:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8B8_SSCALED:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8B8_UINT:			return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8B8_SINT:			return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8B8_SRGB:			return TextureFormat(TextureFormat::sRGB,	TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_R8G8B8A8_UNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
+		case VK_FORMAT_R8G8B8A8_SNORM:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT8);
+		case VK_FORMAT_R8G8B8A8_USCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8B8A8_SSCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8B8A8_UINT:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_R8G8B8A8_SINT:		return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_R8G8B8A8_SRGB:		return TextureFormat(TextureFormat::sRGBA,	TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_R10G10B10A2_UNORM:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT_1010102_REV);
+		case VK_FORMAT_R10G10B10A2_SNORM:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT_1010102_REV);
+		case VK_FORMAT_R10G10B10A2_UINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT_1010102_REV);
+		case VK_FORMAT_R10G10B10A2_SINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT_1010102_REV);
+		case VK_FORMAT_R10G10B10A2_USCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT_1010102_REV);
+		case VK_FORMAT_R10G10B10A2_SSCALED:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT_1010102_REV);
+
+		case VK_FORMAT_R16_UNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::UNORM_INT16);
+		case VK_FORMAT_R16_SNORM:			return TextureFormat(TextureFormat::R,		TextureFormat::SNORM_INT16);
+		case VK_FORMAT_R16_USCALED:			return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16_SSCALED:			return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16_UINT:			return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16_SINT:			return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16_SFLOAT:			return TextureFormat(TextureFormat::R,		TextureFormat::HALF_FLOAT);
+
+		case VK_FORMAT_R16G16_UNORM:		return TextureFormat(TextureFormat::RG,		TextureFormat::UNORM_INT16);
+		case VK_FORMAT_R16G16_SNORM:		return TextureFormat(TextureFormat::RG,		TextureFormat::SNORM_INT16);
+		case VK_FORMAT_R16G16_USCALED:		return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16_SSCALED:		return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16_UINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16_SINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16_SFLOAT:		return TextureFormat(TextureFormat::RG,		TextureFormat::HALF_FLOAT);
+
+		case VK_FORMAT_R16G16B16_UNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT16);
+		case VK_FORMAT_R16G16B16_SNORM:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SNORM_INT16);
+		case VK_FORMAT_R16G16B16_USCALED:	return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16B16_SSCALED:	return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16B16_UINT:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16B16_SINT:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16B16_SFLOAT:	return TextureFormat(TextureFormat::RGB,	TextureFormat::HALF_FLOAT);
+
+		case VK_FORMAT_R16G16B16A16_UNORM:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT16);
+		case VK_FORMAT_R16G16B16A16_SNORM:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SNORM_INT16);
+		case VK_FORMAT_R16G16B16A16_USCALED:return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16B16A16_SSCALED:return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16B16A16_UINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT16);
+		case VK_FORMAT_R16G16B16A16_SINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT16);
+		case VK_FORMAT_R16G16B16A16_SFLOAT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::HALF_FLOAT);
+
+		case VK_FORMAT_R32_UINT:			return TextureFormat(TextureFormat::R,		TextureFormat::UNSIGNED_INT32);
+		case VK_FORMAT_R32_SINT:			return TextureFormat(TextureFormat::R,		TextureFormat::SIGNED_INT32);
+		case VK_FORMAT_R32_SFLOAT:			return TextureFormat(TextureFormat::R,		TextureFormat::FLOAT);
+
+		case VK_FORMAT_R32G32_UINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::UNSIGNED_INT32);
+		case VK_FORMAT_R32G32_SINT:			return TextureFormat(TextureFormat::RG,		TextureFormat::SIGNED_INT32);
+		case VK_FORMAT_R32G32_SFLOAT:		return TextureFormat(TextureFormat::RG,		TextureFormat::FLOAT);
+
+		case VK_FORMAT_R32G32B32_UINT:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT32);
+		case VK_FORMAT_R32G32B32_SINT:		return TextureFormat(TextureFormat::RGB,	TextureFormat::SIGNED_INT32);
+		case VK_FORMAT_R32G32B32_SFLOAT:	return TextureFormat(TextureFormat::RGB,	TextureFormat::FLOAT);
+
+		case VK_FORMAT_R32G32B32A32_UINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNSIGNED_INT32);
+		case VK_FORMAT_R32G32B32A32_SINT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::SIGNED_INT32);
+		case VK_FORMAT_R32G32B32A32_SFLOAT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT);
+
+		case VK_FORMAT_R64_SFLOAT:			return TextureFormat(TextureFormat::R,		TextureFormat::FLOAT64);
+		case VK_FORMAT_R64G64_SFLOAT:		return TextureFormat(TextureFormat::RG,		TextureFormat::FLOAT64);
+		case VK_FORMAT_R64G64B64_SFLOAT:	return TextureFormat(TextureFormat::RGB,	TextureFormat::FLOAT64);
+		case VK_FORMAT_R64G64B64A64_SFLOAT:	return TextureFormat(TextureFormat::RGBA,	TextureFormat::FLOAT64);
+
+		case VK_FORMAT_R11G11B10_UFLOAT:	return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT_11F_11F_10F_REV);
+		case VK_FORMAT_R9G9B9E5_UFLOAT:		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNSIGNED_INT_999_E5_REV);
+
+		case VK_FORMAT_B8G8R8_UNORM:		return TextureFormat(TextureFormat::BGR,	TextureFormat::UNORM_INT8);
+		case VK_FORMAT_B8G8R8_SNORM:		return TextureFormat(TextureFormat::BGR,	TextureFormat::SNORM_INT8);
+		case VK_FORMAT_B8G8R8_USCALED:		return TextureFormat(TextureFormat::BGR,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_B8G8R8_SSCALED:		return TextureFormat(TextureFormat::BGR,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_B8G8R8_UINT:			return TextureFormat(TextureFormat::BGR,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_B8G8R8_SINT:			return TextureFormat(TextureFormat::BGR,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_B8G8R8_SRGB:			return TextureFormat(TextureFormat::sBGR,	TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_B8G8R8A8_UNORM:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNORM_INT8);
+		case VK_FORMAT_B8G8R8A8_SNORM:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::SNORM_INT8);
+		case VK_FORMAT_B8G8R8A8_USCALED:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_B8G8R8A8_SSCALED:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_B8G8R8A8_UINT:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNSIGNED_INT8);
+		case VK_FORMAT_B8G8R8A8_SINT:		return TextureFormat(TextureFormat::BGRA,	TextureFormat::SIGNED_INT8);
+		case VK_FORMAT_B8G8R8A8_SRGB:		return TextureFormat(TextureFormat::sBGRA,	TextureFormat::UNORM_INT8);
+
+		case VK_FORMAT_D16_UNORM:			return TextureFormat(TextureFormat::D,		TextureFormat::UNORM_INT16);
+		case VK_FORMAT_D24_UNORM_X8:		return TextureFormat(TextureFormat::D,		TextureFormat::UNSIGNED_INT_24_8_REV);
+		case VK_FORMAT_D32_SFLOAT:			return TextureFormat(TextureFormat::D,		TextureFormat::FLOAT);
+
+		case VK_FORMAT_S8_UINT:				return TextureFormat(TextureFormat::S,		TextureFormat::UNSIGNED_INT8);
+
+		// \note There is no standard interleaved memory layout for DS formats; buffer-image copies
+		//		 will always operate on either D or S aspect only. See Khronos bug 12998
+		case VK_FORMAT_D16_UNORM_S8_UINT:	return TextureFormat(TextureFormat::DS,		TextureFormat::UNSIGNED_INT_16_8_8);
+		case VK_FORMAT_D24_UNORM_S8_UINT:	return TextureFormat(TextureFormat::DS,		TextureFormat::UNSIGNED_INT_24_8_REV);
+		case VK_FORMAT_D32_SFLOAT_S8_UINT:	return TextureFormat(TextureFormat::DS,		TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
+
+		case VK_FORMAT_B10G10R10A2_UNORM:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNORM_INT_1010102_REV);
+		case VK_FORMAT_B10G10R10A2_SNORM:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::SNORM_INT_1010102_REV);
+		case VK_FORMAT_B10G10R10A2_USCALED:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNSIGNED_INT_1010102_REV);
+		case VK_FORMAT_B10G10R10A2_SSCALED:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::SIGNED_INT_1010102_REV);
+		case VK_FORMAT_B10G10R10A2_UINT:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::UNSIGNED_INT_1010102_REV);
+		case VK_FORMAT_B10G10R10A2_SINT:	return TextureFormat(TextureFormat::BGRA,	TextureFormat::SIGNED_INT_1010102_REV);
+
+		default:
+			TCU_THROW(InternalError, "Unknown image format");
+	}
+}
+
+tcu::CompressedTexFormat mapVkCompressedFormat (VkFormat format)
+{
+	switch (format)
+	{
+		case VK_FORMAT_ETC2_R8G8B8_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8;
+		case VK_FORMAT_ETC2_R8G8B8_SRGB:		return tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8;
+		case VK_FORMAT_ETC2_R8G8B8A1_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1;
+		case VK_FORMAT_ETC2_R8G8B8A1_SRGB:		return tcu::COMPRESSEDTEXFORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1;
+		case VK_FORMAT_ETC2_R8G8B8A8_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_RGBA8;
+		case VK_FORMAT_ETC2_R8G8B8A8_SRGB:		return tcu::COMPRESSEDTEXFORMAT_ETC2_EAC_SRGB8_ALPHA8;
+		case VK_FORMAT_EAC_R11_UNORM:			return tcu::COMPRESSEDTEXFORMAT_EAC_R11;
+		case VK_FORMAT_EAC_R11_SNORM:			return tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_R11;
+		case VK_FORMAT_EAC_R11G11_UNORM:		return tcu::COMPRESSEDTEXFORMAT_EAC_RG11;
+		case VK_FORMAT_EAC_R11G11_SNORM:		return tcu::COMPRESSEDTEXFORMAT_EAC_SIGNED_RG11;
+		case VK_FORMAT_ASTC_4x4_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_RGBA;
+		case VK_FORMAT_ASTC_4x4_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_4x4_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_5x4_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_5x4_RGBA;
+		case VK_FORMAT_ASTC_5x4_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_5x5_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_RGBA;
+		case VK_FORMAT_ASTC_5x5_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_5x5_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_6x5_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_RGBA;
+		case VK_FORMAT_ASTC_6x5_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_6x5_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_6x6_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_RGBA;
+		case VK_FORMAT_ASTC_6x6_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_6x6_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_8x5_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x5_RGBA;
+		case VK_FORMAT_ASTC_8x5_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_8x6_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_RGBA;
+		case VK_FORMAT_ASTC_8x6_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x6_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_8x8_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_RGBA;
+		case VK_FORMAT_ASTC_8x8_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_8x8_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_10x5_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_RGBA;
+		case VK_FORMAT_ASTC_10x5_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x5_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_10x6_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_RGBA;
+		case VK_FORMAT_ASTC_10x6_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x6_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_10x8_UNORM:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_RGBA;
+		case VK_FORMAT_ASTC_10x8_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x8_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_10x10_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_RGBA;
+		case VK_FORMAT_ASTC_10x10_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_10x10_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_12x10_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_RGBA;
+		case VK_FORMAT_ASTC_12x10_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_12x10_SRGB8_ALPHA8;
+		case VK_FORMAT_ASTC_12x12_UNORM:		return tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_RGBA;
+		case VK_FORMAT_ASTC_12x12_SRGB:			return tcu::COMPRESSEDTEXFORMAT_ASTC_12x12_SRGB8_ALPHA8;
+		default:
+			break;
+	}
+
+	return tcu::COMPRESSEDTEXFORMAT_LAST;
+}
+
+VkChannelMapping getFormatChannelMapping (VkFormat format)
+{
+	using tcu::TextureFormat;
+
+	static const VkChannelMapping	R		= {	VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ONE	};
+	static const VkChannelMapping	RG		= {	VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_G,		VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ONE	};
+	static const VkChannelMapping	RGB		= {	VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_G,		VK_CHANNEL_SWIZZLE_B,		VK_CHANNEL_SWIZZLE_ONE	};
+	static const VkChannelMapping	RGBA	= {	VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_G,		VK_CHANNEL_SWIZZLE_B,		VK_CHANNEL_SWIZZLE_A	};
+	static const VkChannelMapping	S		= { VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_A	};
+	static const VkChannelMapping	DS		= {	VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_ZERO,	VK_CHANNEL_SWIZZLE_A	};
+	static const VkChannelMapping	BGRA	= {	VK_CHANNEL_SWIZZLE_B,		VK_CHANNEL_SWIZZLE_G,		VK_CHANNEL_SWIZZLE_R,		VK_CHANNEL_SWIZZLE_A	};
+
+	if (format == VK_FORMAT_UNDEFINED)
+		return RGBA;
+
+	const tcu::TextureFormat tcuFormat = (isCompressedFormat(format)) ? tcu::getUncompressedFormat(mapVkCompressedFormat(format))
+																	  : mapVkFormat(format);
+
+	switch (tcuFormat.order)
+	{
+		case TextureFormat::R:		return R;
+		case TextureFormat::RG:		return RG;
+		case TextureFormat::RGB:	return RGB;
+		case TextureFormat::RGBA:	return RGBA;
+		case TextureFormat::BGRA:	return BGRA;
+		case TextureFormat::sR:		return R;
+		case TextureFormat::sRG:	return RG;
+		case TextureFormat::sRGB:	return RGB;
+		case TextureFormat::sRGBA:	return RGBA;
+		case TextureFormat::D:		return R;
+		case TextureFormat::S:		return S;
+		case TextureFormat::DS:		return DS;
+		default:
+			break;
+	}
+
+	DE_ASSERT(false);
+	return RGBA;
+}
+
+static bool isScaledFormat (VkFormat format)
+{
+	// update this mapping if VkFormat changes
+	DE_STATIC_ASSERT(VK_FORMAT_LAST == 174);
+
+	switch (format)
+	{
+		case VK_FORMAT_R4G4_USCALED:
+		case VK_FORMAT_R4G4B4A4_USCALED:
+		case VK_FORMAT_R5G6B5_USCALED:
+		case VK_FORMAT_R5G5B5A1_USCALED:
+		case VK_FORMAT_R8_USCALED:
+		case VK_FORMAT_R8_SSCALED:
+		case VK_FORMAT_R8G8_USCALED:
+		case VK_FORMAT_R8G8_SSCALED:
+		case VK_FORMAT_R8G8B8_USCALED:
+		case VK_FORMAT_R8G8B8_SSCALED:
+		case VK_FORMAT_R8G8B8A8_USCALED:
+		case VK_FORMAT_R8G8B8A8_SSCALED:
+		case VK_FORMAT_R10G10B10A2_USCALED:
+		case VK_FORMAT_R10G10B10A2_SSCALED:
+		case VK_FORMAT_R16_USCALED:
+		case VK_FORMAT_R16_SSCALED:
+		case VK_FORMAT_R16G16_USCALED:
+		case VK_FORMAT_R16G16_SSCALED:
+		case VK_FORMAT_R16G16B16_USCALED:
+		case VK_FORMAT_R16G16B16_SSCALED:
+		case VK_FORMAT_R16G16B16A16_USCALED:
+		case VK_FORMAT_R16G16B16A16_SSCALED:
+		case VK_FORMAT_B5G6R5_USCALED:
+		case VK_FORMAT_B8G8R8_USCALED:
+		case VK_FORMAT_B8G8R8_SSCALED:
+		case VK_FORMAT_B8G8R8A8_USCALED:
+		case VK_FORMAT_B8G8R8A8_SSCALED:
+		case VK_FORMAT_B10G10R10A2_USCALED:
+		case VK_FORMAT_B10G10R10A2_SSCALED:
+			return true;
+
+		default:
+			return false;
+	}
+}
+
+static bool fullTextureFormatRoundTripSupported (VkFormat format)
+{
+	if (isScaledFormat(format))
+	{
+		// *SCALED formats get mapped to correspoding (u)int formats since
+		// accessing them through (float) getPixel/setPixel has same behavior
+		// as in shader access in Vulkan.
+		// Unfortunately full round-trip between tcu::TextureFormat and VkFormat
+		// for most SCALED formats is not supported though.
+
+		const tcu::TextureFormat	tcuFormat	= mapVkFormat(format);
+
+		switch (tcuFormat.type)
+		{
+			case tcu::TextureFormat::UNSIGNED_INT8:
+			case tcu::TextureFormat::UNSIGNED_INT16:
+			case tcu::TextureFormat::UNSIGNED_INT32:
+			case tcu::TextureFormat::SIGNED_INT8:
+			case tcu::TextureFormat::SIGNED_INT16:
+			case tcu::TextureFormat::SIGNED_INT32:
+			case tcu::TextureFormat::UNSIGNED_INT_1010102_REV:
+			case tcu::TextureFormat::SIGNED_INT_1010102_REV:
+				return false;
+
+			default:
+				return true;
+		}
+	}
+	else
+		return (format != VK_FORMAT_UNDEFINED);
+}
+
+void imageUtilSelfTest (void)
+{
+	for (int formatNdx = 0; formatNdx < VK_FORMAT_LAST; formatNdx++)
+	{
+		const VkFormat	format	= (VkFormat)formatNdx;
+
+		if (format != VK_FORMAT_UNDEFINED && !isCompressedFormat(format))
+		{
+			const tcu::TextureFormat	tcuFormat		= mapVkFormat(format);
+			const VkFormat				remappedFormat	= mapTextureFormat(tcuFormat);
+
+			DE_TEST_ASSERT(isValid(tcuFormat));
+
+			if (fullTextureFormatRoundTripSupported(format))
+				DE_TEST_ASSERT(format == remappedFormat);
+		}
+	}
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkImageUtil.hpp b/external/vulkancts/framework/vulkan/vkImageUtil.hpp
new file mode 100644
index 0000000..f8e668d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkImageUtil.hpp
@@ -0,0 +1,64 @@
+#ifndef _VKIMAGEUTIL_HPP
+#define _VKIMAGEUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for images.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "tcuTexture.hpp"
+#include "tcuCompressedTexture.hpp"
+
+namespace vk
+{
+
+bool						isFloatFormat			(VkFormat format);
+bool						isUnormFormat			(VkFormat format);
+bool						isSnormFormat			(VkFormat format);
+bool						isIntFormat				(VkFormat format);
+bool						isUintFormat			(VkFormat format);
+bool						isDepthStencilFormat	(VkFormat format);
+bool						isCompressedFormat		(VkFormat format);
+
+tcu::TextureFormat			mapVkFormat				(VkFormat format);
+tcu::CompressedTexFormat	mapVkCompressedFormat	(VkFormat format);
+VkChannelMapping			getFormatChannelMapping	(VkFormat format);
+
+VkFormat					mapTextureFormat		(const tcu::TextureFormat& format);
+
+void						imageUtilSelfTest		(void);
+
+} // vk
+
+#endif // _VKIMAGEUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkInitDeviceFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkInitDeviceFunctionPointers.inl
new file mode 100644
index 0000000..0c4dacb
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkInitDeviceFunctionPointers.inl
@@ -0,0 +1,132 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+m_vk.destroyDevice									= (DestroyDeviceFunc)									GET_PROC_ADDR("vkDestroyDevice");
+m_vk.getDeviceQueue									= (GetDeviceQueueFunc)									GET_PROC_ADDR("vkGetDeviceQueue");
+m_vk.queueSubmit									= (QueueSubmitFunc)										GET_PROC_ADDR("vkQueueSubmit");
+m_vk.queueWaitIdle									= (QueueWaitIdleFunc)									GET_PROC_ADDR("vkQueueWaitIdle");
+m_vk.deviceWaitIdle									= (DeviceWaitIdleFunc)									GET_PROC_ADDR("vkDeviceWaitIdle");
+m_vk.allocMemory									= (AllocMemoryFunc)										GET_PROC_ADDR("vkAllocMemory");
+m_vk.freeMemory										= (FreeMemoryFunc)										GET_PROC_ADDR("vkFreeMemory");
+m_vk.mapMemory										= (MapMemoryFunc)										GET_PROC_ADDR("vkMapMemory");
+m_vk.unmapMemory									= (UnmapMemoryFunc)										GET_PROC_ADDR("vkUnmapMemory");
+m_vk.flushMappedMemoryRanges						= (FlushMappedMemoryRangesFunc)							GET_PROC_ADDR("vkFlushMappedMemoryRanges");
+m_vk.invalidateMappedMemoryRanges					= (InvalidateMappedMemoryRangesFunc)					GET_PROC_ADDR("vkInvalidateMappedMemoryRanges");
+m_vk.getDeviceMemoryCommitment						= (GetDeviceMemoryCommitmentFunc)						GET_PROC_ADDR("vkGetDeviceMemoryCommitment");
+m_vk.bindBufferMemory								= (BindBufferMemoryFunc)								GET_PROC_ADDR("vkBindBufferMemory");
+m_vk.bindImageMemory								= (BindImageMemoryFunc)									GET_PROC_ADDR("vkBindImageMemory");
+m_vk.getBufferMemoryRequirements					= (GetBufferMemoryRequirementsFunc)						GET_PROC_ADDR("vkGetBufferMemoryRequirements");
+m_vk.getImageMemoryRequirements						= (GetImageMemoryRequirementsFunc)						GET_PROC_ADDR("vkGetImageMemoryRequirements");
+m_vk.getImageSparseMemoryRequirements				= (GetImageSparseMemoryRequirementsFunc)				GET_PROC_ADDR("vkGetImageSparseMemoryRequirements");
+m_vk.getPhysicalDeviceSparseImageFormatProperties	= (GetPhysicalDeviceSparseImageFormatPropertiesFunc)	GET_PROC_ADDR("vkGetPhysicalDeviceSparseImageFormatProperties");
+m_vk.queueBindSparseBufferMemory					= (QueueBindSparseBufferMemoryFunc)						GET_PROC_ADDR("vkQueueBindSparseBufferMemory");
+m_vk.queueBindSparseImageOpaqueMemory				= (QueueBindSparseImageOpaqueMemoryFunc)				GET_PROC_ADDR("vkQueueBindSparseImageOpaqueMemory");
+m_vk.queueBindSparseImageMemory						= (QueueBindSparseImageMemoryFunc)						GET_PROC_ADDR("vkQueueBindSparseImageMemory");
+m_vk.createFence									= (CreateFenceFunc)										GET_PROC_ADDR("vkCreateFence");
+m_vk.destroyFence									= (DestroyFenceFunc)									GET_PROC_ADDR("vkDestroyFence");
+m_vk.resetFences									= (ResetFencesFunc)										GET_PROC_ADDR("vkResetFences");
+m_vk.getFenceStatus									= (GetFenceStatusFunc)									GET_PROC_ADDR("vkGetFenceStatus");
+m_vk.waitForFences									= (WaitForFencesFunc)									GET_PROC_ADDR("vkWaitForFences");
+m_vk.createSemaphore								= (CreateSemaphoreFunc)									GET_PROC_ADDR("vkCreateSemaphore");
+m_vk.destroySemaphore								= (DestroySemaphoreFunc)								GET_PROC_ADDR("vkDestroySemaphore");
+m_vk.queueSignalSemaphore							= (QueueSignalSemaphoreFunc)							GET_PROC_ADDR("vkQueueSignalSemaphore");
+m_vk.queueWaitSemaphore								= (QueueWaitSemaphoreFunc)								GET_PROC_ADDR("vkQueueWaitSemaphore");
+m_vk.createEvent									= (CreateEventFunc)										GET_PROC_ADDR("vkCreateEvent");
+m_vk.destroyEvent									= (DestroyEventFunc)									GET_PROC_ADDR("vkDestroyEvent");
+m_vk.getEventStatus									= (GetEventStatusFunc)									GET_PROC_ADDR("vkGetEventStatus");
+m_vk.setEvent										= (SetEventFunc)										GET_PROC_ADDR("vkSetEvent");
+m_vk.resetEvent										= (ResetEventFunc)										GET_PROC_ADDR("vkResetEvent");
+m_vk.createQueryPool								= (CreateQueryPoolFunc)									GET_PROC_ADDR("vkCreateQueryPool");
+m_vk.destroyQueryPool								= (DestroyQueryPoolFunc)								GET_PROC_ADDR("vkDestroyQueryPool");
+m_vk.getQueryPoolResults							= (GetQueryPoolResultsFunc)								GET_PROC_ADDR("vkGetQueryPoolResults");
+m_vk.createBuffer									= (CreateBufferFunc)									GET_PROC_ADDR("vkCreateBuffer");
+m_vk.destroyBuffer									= (DestroyBufferFunc)									GET_PROC_ADDR("vkDestroyBuffer");
+m_vk.createBufferView								= (CreateBufferViewFunc)								GET_PROC_ADDR("vkCreateBufferView");
+m_vk.destroyBufferView								= (DestroyBufferViewFunc)								GET_PROC_ADDR("vkDestroyBufferView");
+m_vk.createImage									= (CreateImageFunc)										GET_PROC_ADDR("vkCreateImage");
+m_vk.destroyImage									= (DestroyImageFunc)									GET_PROC_ADDR("vkDestroyImage");
+m_vk.getImageSubresourceLayout						= (GetImageSubresourceLayoutFunc)						GET_PROC_ADDR("vkGetImageSubresourceLayout");
+m_vk.createImageView								= (CreateImageViewFunc)									GET_PROC_ADDR("vkCreateImageView");
+m_vk.destroyImageView								= (DestroyImageViewFunc)								GET_PROC_ADDR("vkDestroyImageView");
+m_vk.createShaderModule								= (CreateShaderModuleFunc)								GET_PROC_ADDR("vkCreateShaderModule");
+m_vk.destroyShaderModule							= (DestroyShaderModuleFunc)								GET_PROC_ADDR("vkDestroyShaderModule");
+m_vk.createShader									= (CreateShaderFunc)									GET_PROC_ADDR("vkCreateShader");
+m_vk.destroyShader									= (DestroyShaderFunc)									GET_PROC_ADDR("vkDestroyShader");
+m_vk.createPipelineCache							= (CreatePipelineCacheFunc)								GET_PROC_ADDR("vkCreatePipelineCache");
+m_vk.destroyPipelineCache							= (DestroyPipelineCacheFunc)							GET_PROC_ADDR("vkDestroyPipelineCache");
+m_vk.getPipelineCacheSize							= (GetPipelineCacheSizeFunc)							GET_PROC_ADDR("vkGetPipelineCacheSize");
+m_vk.getPipelineCacheData							= (GetPipelineCacheDataFunc)							GET_PROC_ADDR("vkGetPipelineCacheData");
+m_vk.mergePipelineCaches							= (MergePipelineCachesFunc)								GET_PROC_ADDR("vkMergePipelineCaches");
+m_vk.createGraphicsPipelines						= (CreateGraphicsPipelinesFunc)							GET_PROC_ADDR("vkCreateGraphicsPipelines");
+m_vk.createComputePipelines							= (CreateComputePipelinesFunc)							GET_PROC_ADDR("vkCreateComputePipelines");
+m_vk.destroyPipeline								= (DestroyPipelineFunc)									GET_PROC_ADDR("vkDestroyPipeline");
+m_vk.createPipelineLayout							= (CreatePipelineLayoutFunc)							GET_PROC_ADDR("vkCreatePipelineLayout");
+m_vk.destroyPipelineLayout							= (DestroyPipelineLayoutFunc)							GET_PROC_ADDR("vkDestroyPipelineLayout");
+m_vk.createSampler									= (CreateSamplerFunc)									GET_PROC_ADDR("vkCreateSampler");
+m_vk.destroySampler									= (DestroySamplerFunc)									GET_PROC_ADDR("vkDestroySampler");
+m_vk.createDescriptorSetLayout						= (CreateDescriptorSetLayoutFunc)						GET_PROC_ADDR("vkCreateDescriptorSetLayout");
+m_vk.destroyDescriptorSetLayout						= (DestroyDescriptorSetLayoutFunc)						GET_PROC_ADDR("vkDestroyDescriptorSetLayout");
+m_vk.createDescriptorPool							= (CreateDescriptorPoolFunc)							GET_PROC_ADDR("vkCreateDescriptorPool");
+m_vk.destroyDescriptorPool							= (DestroyDescriptorPoolFunc)							GET_PROC_ADDR("vkDestroyDescriptorPool");
+m_vk.resetDescriptorPool							= (ResetDescriptorPoolFunc)								GET_PROC_ADDR("vkResetDescriptorPool");
+m_vk.allocDescriptorSets							= (AllocDescriptorSetsFunc)								GET_PROC_ADDR("vkAllocDescriptorSets");
+m_vk.freeDescriptorSets								= (FreeDescriptorSetsFunc)								GET_PROC_ADDR("vkFreeDescriptorSets");
+m_vk.updateDescriptorSets							= (UpdateDescriptorSetsFunc)							GET_PROC_ADDR("vkUpdateDescriptorSets");
+m_vk.createFramebuffer								= (CreateFramebufferFunc)								GET_PROC_ADDR("vkCreateFramebuffer");
+m_vk.destroyFramebuffer								= (DestroyFramebufferFunc)								GET_PROC_ADDR("vkDestroyFramebuffer");
+m_vk.createRenderPass								= (CreateRenderPassFunc)								GET_PROC_ADDR("vkCreateRenderPass");
+m_vk.destroyRenderPass								= (DestroyRenderPassFunc)								GET_PROC_ADDR("vkDestroyRenderPass");
+m_vk.getRenderAreaGranularity						= (GetRenderAreaGranularityFunc)						GET_PROC_ADDR("vkGetRenderAreaGranularity");
+m_vk.createCommandPool								= (CreateCommandPoolFunc)								GET_PROC_ADDR("vkCreateCommandPool");
+m_vk.destroyCommandPool								= (DestroyCommandPoolFunc)								GET_PROC_ADDR("vkDestroyCommandPool");
+m_vk.resetCommandPool								= (ResetCommandPoolFunc)								GET_PROC_ADDR("vkResetCommandPool");
+m_vk.createCommandBuffer							= (CreateCommandBufferFunc)								GET_PROC_ADDR("vkCreateCommandBuffer");
+m_vk.destroyCommandBuffer							= (DestroyCommandBufferFunc)							GET_PROC_ADDR("vkDestroyCommandBuffer");
+m_vk.beginCommandBuffer								= (BeginCommandBufferFunc)								GET_PROC_ADDR("vkBeginCommandBuffer");
+m_vk.endCommandBuffer								= (EndCommandBufferFunc)								GET_PROC_ADDR("vkEndCommandBuffer");
+m_vk.resetCommandBuffer								= (ResetCommandBufferFunc)								GET_PROC_ADDR("vkResetCommandBuffer");
+m_vk.cmdBindPipeline								= (CmdBindPipelineFunc)									GET_PROC_ADDR("vkCmdBindPipeline");
+m_vk.cmdSetViewport									= (CmdSetViewportFunc)									GET_PROC_ADDR("vkCmdSetViewport");
+m_vk.cmdSetScissor									= (CmdSetScissorFunc)									GET_PROC_ADDR("vkCmdSetScissor");
+m_vk.cmdSetLineWidth								= (CmdSetLineWidthFunc)									GET_PROC_ADDR("vkCmdSetLineWidth");
+m_vk.cmdSetDepthBias								= (CmdSetDepthBiasFunc)									GET_PROC_ADDR("vkCmdSetDepthBias");
+m_vk.cmdSetBlendConstants							= (CmdSetBlendConstantsFunc)							GET_PROC_ADDR("vkCmdSetBlendConstants");
+m_vk.cmdSetDepthBounds								= (CmdSetDepthBoundsFunc)								GET_PROC_ADDR("vkCmdSetDepthBounds");
+m_vk.cmdSetStencilCompareMask						= (CmdSetStencilCompareMaskFunc)						GET_PROC_ADDR("vkCmdSetStencilCompareMask");
+m_vk.cmdSetStencilWriteMask							= (CmdSetStencilWriteMaskFunc)							GET_PROC_ADDR("vkCmdSetStencilWriteMask");
+m_vk.cmdSetStencilReference							= (CmdSetStencilReferenceFunc)							GET_PROC_ADDR("vkCmdSetStencilReference");
+m_vk.cmdBindDescriptorSets							= (CmdBindDescriptorSetsFunc)							GET_PROC_ADDR("vkCmdBindDescriptorSets");
+m_vk.cmdBindIndexBuffer								= (CmdBindIndexBufferFunc)								GET_PROC_ADDR("vkCmdBindIndexBuffer");
+m_vk.cmdBindVertexBuffers							= (CmdBindVertexBuffersFunc)							GET_PROC_ADDR("vkCmdBindVertexBuffers");
+m_vk.cmdDraw										= (CmdDrawFunc)											GET_PROC_ADDR("vkCmdDraw");
+m_vk.cmdDrawIndexed									= (CmdDrawIndexedFunc)									GET_PROC_ADDR("vkCmdDrawIndexed");
+m_vk.cmdDrawIndirect								= (CmdDrawIndirectFunc)									GET_PROC_ADDR("vkCmdDrawIndirect");
+m_vk.cmdDrawIndexedIndirect							= (CmdDrawIndexedIndirectFunc)							GET_PROC_ADDR("vkCmdDrawIndexedIndirect");
+m_vk.cmdDispatch									= (CmdDispatchFunc)										GET_PROC_ADDR("vkCmdDispatch");
+m_vk.cmdDispatchIndirect							= (CmdDispatchIndirectFunc)								GET_PROC_ADDR("vkCmdDispatchIndirect");
+m_vk.cmdCopyBuffer									= (CmdCopyBufferFunc)									GET_PROC_ADDR("vkCmdCopyBuffer");
+m_vk.cmdCopyImage									= (CmdCopyImageFunc)									GET_PROC_ADDR("vkCmdCopyImage");
+m_vk.cmdBlitImage									= (CmdBlitImageFunc)									GET_PROC_ADDR("vkCmdBlitImage");
+m_vk.cmdCopyBufferToImage							= (CmdCopyBufferToImageFunc)							GET_PROC_ADDR("vkCmdCopyBufferToImage");
+m_vk.cmdCopyImageToBuffer							= (CmdCopyImageToBufferFunc)							GET_PROC_ADDR("vkCmdCopyImageToBuffer");
+m_vk.cmdUpdateBuffer								= (CmdUpdateBufferFunc)									GET_PROC_ADDR("vkCmdUpdateBuffer");
+m_vk.cmdFillBuffer									= (CmdFillBufferFunc)									GET_PROC_ADDR("vkCmdFillBuffer");
+m_vk.cmdClearColorImage								= (CmdClearColorImageFunc)								GET_PROC_ADDR("vkCmdClearColorImage");
+m_vk.cmdClearDepthStencilImage						= (CmdClearDepthStencilImageFunc)						GET_PROC_ADDR("vkCmdClearDepthStencilImage");
+m_vk.cmdClearColorAttachment						= (CmdClearColorAttachmentFunc)							GET_PROC_ADDR("vkCmdClearColorAttachment");
+m_vk.cmdClearDepthStencilAttachment					= (CmdClearDepthStencilAttachmentFunc)					GET_PROC_ADDR("vkCmdClearDepthStencilAttachment");
+m_vk.cmdResolveImage								= (CmdResolveImageFunc)									GET_PROC_ADDR("vkCmdResolveImage");
+m_vk.cmdSetEvent									= (CmdSetEventFunc)										GET_PROC_ADDR("vkCmdSetEvent");
+m_vk.cmdResetEvent									= (CmdResetEventFunc)									GET_PROC_ADDR("vkCmdResetEvent");
+m_vk.cmdWaitEvents									= (CmdWaitEventsFunc)									GET_PROC_ADDR("vkCmdWaitEvents");
+m_vk.cmdPipelineBarrier								= (CmdPipelineBarrierFunc)								GET_PROC_ADDR("vkCmdPipelineBarrier");
+m_vk.cmdBeginQuery									= (CmdBeginQueryFunc)									GET_PROC_ADDR("vkCmdBeginQuery");
+m_vk.cmdEndQuery									= (CmdEndQueryFunc)										GET_PROC_ADDR("vkCmdEndQuery");
+m_vk.cmdResetQueryPool								= (CmdResetQueryPoolFunc)								GET_PROC_ADDR("vkCmdResetQueryPool");
+m_vk.cmdWriteTimestamp								= (CmdWriteTimestampFunc)								GET_PROC_ADDR("vkCmdWriteTimestamp");
+m_vk.cmdCopyQueryPoolResults						= (CmdCopyQueryPoolResultsFunc)							GET_PROC_ADDR("vkCmdCopyQueryPoolResults");
+m_vk.cmdPushConstants								= (CmdPushConstantsFunc)								GET_PROC_ADDR("vkCmdPushConstants");
+m_vk.cmdBeginRenderPass								= (CmdBeginRenderPassFunc)								GET_PROC_ADDR("vkCmdBeginRenderPass");
+m_vk.cmdNextSubpass									= (CmdNextSubpassFunc)									GET_PROC_ADDR("vkCmdNextSubpass");
+m_vk.cmdEndRenderPass								= (CmdEndRenderPassFunc)								GET_PROC_ADDR("vkCmdEndRenderPass");
+m_vk.cmdExecuteCommands								= (CmdExecuteCommandsFunc)								GET_PROC_ADDR("vkCmdExecuteCommands");
diff --git a/external/vulkancts/framework/vulkan/vkInitInstanceFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkInitInstanceFunctionPointers.inl
new file mode 100644
index 0000000..1bd339c
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkInitInstanceFunctionPointers.inl
@@ -0,0 +1,15 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+m_vk.destroyInstance						= (DestroyInstanceFunc)							GET_PROC_ADDR("vkDestroyInstance");
+m_vk.enumeratePhysicalDevices				= (EnumeratePhysicalDevicesFunc)				GET_PROC_ADDR("vkEnumeratePhysicalDevices");
+m_vk.getPhysicalDeviceFeatures				= (GetPhysicalDeviceFeaturesFunc)				GET_PROC_ADDR("vkGetPhysicalDeviceFeatures");
+m_vk.getPhysicalDeviceFormatProperties		= (GetPhysicalDeviceFormatPropertiesFunc)		GET_PROC_ADDR("vkGetPhysicalDeviceFormatProperties");
+m_vk.getPhysicalDeviceImageFormatProperties	= (GetPhysicalDeviceImageFormatPropertiesFunc)	GET_PROC_ADDR("vkGetPhysicalDeviceImageFormatProperties");
+m_vk.getPhysicalDeviceProperties			= (GetPhysicalDevicePropertiesFunc)				GET_PROC_ADDR("vkGetPhysicalDeviceProperties");
+m_vk.getPhysicalDeviceQueueFamilyProperties	= (GetPhysicalDeviceQueueFamilyPropertiesFunc)	GET_PROC_ADDR("vkGetPhysicalDeviceQueueFamilyProperties");
+m_vk.getPhysicalDeviceMemoryProperties		= (GetPhysicalDeviceMemoryPropertiesFunc)		GET_PROC_ADDR("vkGetPhysicalDeviceMemoryProperties");
+m_vk.getDeviceProcAddr						= (GetDeviceProcAddrFunc)						GET_PROC_ADDR("vkGetDeviceProcAddr");
+m_vk.createDevice							= (CreateDeviceFunc)							GET_PROC_ADDR("vkCreateDevice");
+m_vk.enumerateDeviceExtensionProperties		= (EnumerateDeviceExtensionPropertiesFunc)		GET_PROC_ADDR("vkEnumerateDeviceExtensionProperties");
+m_vk.enumerateDeviceLayerProperties			= (EnumerateDeviceLayerPropertiesFunc)			GET_PROC_ADDR("vkEnumerateDeviceLayerProperties");
diff --git a/external/vulkancts/framework/vulkan/vkInitPlatformFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkInitPlatformFunctionPointers.inl
new file mode 100644
index 0000000..480eaac
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkInitPlatformFunctionPointers.inl
@@ -0,0 +1,7 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+m_vk.createInstance							= (CreateInstanceFunc)							GET_PROC_ADDR("vkCreateInstance");
+m_vk.getInstanceProcAddr					= (GetInstanceProcAddrFunc)						GET_PROC_ADDR("vkGetInstanceProcAddr");
+m_vk.enumerateInstanceExtensionProperties	= (EnumerateInstanceExtensionPropertiesFunc)	GET_PROC_ADDR("vkEnumerateInstanceExtensionProperties");
+m_vk.enumerateInstanceLayerProperties		= (EnumerateInstanceLayerPropertiesFunc)		GET_PROC_ADDR("vkEnumerateInstanceLayerProperties");
diff --git a/external/vulkancts/framework/vulkan/vkInstanceDriverImpl.inl b/external/vulkancts/framework/vulkan/vkInstanceDriverImpl.inl
new file mode 100644
index 0000000..4c98d2e
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkInstanceDriverImpl.inl
@@ -0,0 +1,63 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+
+void InstanceDriver::destroyInstance (VkInstance instance) const
+{
+	m_vk.destroyInstance(instance);
+}
+
+VkResult InstanceDriver::enumeratePhysicalDevices (VkInstance instance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) const
+{
+	return m_vk.enumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceFeatures (VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) const
+{
+	return m_vk.getPhysicalDeviceFeatures(physicalDevice, pFeatures);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) const
+{
+	return m_vk.getPhysicalDeviceFormatProperties(physicalDevice, format, pFormatProperties);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceImageFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) const
+{
+	return m_vk.getPhysicalDeviceImageFormatProperties(physicalDevice, format, type, tiling, usage, flags, pImageFormatProperties);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceProperties (VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) const
+{
+	return m_vk.getPhysicalDeviceProperties(physicalDevice, pProperties);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceQueueFamilyProperties (VkPhysicalDevice physicalDevice, deUint32* pCount, VkQueueFamilyProperties* pQueueFamilyProperties) const
+{
+	return m_vk.getPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
+}
+
+VkResult InstanceDriver::getPhysicalDeviceMemoryProperties (VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) const
+{
+	return m_vk.getPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
+}
+
+PFN_vkVoidFunction InstanceDriver::getDeviceProcAddr (VkDevice device, const char* pName) const
+{
+	return m_vk.getDeviceProcAddr(device, pName);
+}
+
+VkResult InstanceDriver::createDevice (VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice) const
+{
+	return m_vk.createDevice(physicalDevice, pCreateInfo, pDevice);
+}
+
+VkResult InstanceDriver::enumerateDeviceExtensionProperties (VkPhysicalDevice physicalDevice, const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const
+{
+	return m_vk.enumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
+}
+
+VkResult InstanceDriver::enumerateDeviceLayerProperties (VkPhysicalDevice physicalDevice, deUint32* pCount, VkLayerProperties* pProperties) const
+{
+	return m_vk.enumerateDeviceLayerProperties(physicalDevice, pCount, pProperties);
+}
diff --git a/external/vulkancts/framework/vulkan/vkInstanceFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkInstanceFunctionPointers.inl
new file mode 100644
index 0000000..e4e072f
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkInstanceFunctionPointers.inl
@@ -0,0 +1,15 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+DestroyInstanceFunc							destroyInstance;
+EnumeratePhysicalDevicesFunc				enumeratePhysicalDevices;
+GetPhysicalDeviceFeaturesFunc				getPhysicalDeviceFeatures;
+GetPhysicalDeviceFormatPropertiesFunc		getPhysicalDeviceFormatProperties;
+GetPhysicalDeviceImageFormatPropertiesFunc	getPhysicalDeviceImageFormatProperties;
+GetPhysicalDevicePropertiesFunc				getPhysicalDeviceProperties;
+GetPhysicalDeviceQueueFamilyPropertiesFunc	getPhysicalDeviceQueueFamilyProperties;
+GetPhysicalDeviceMemoryPropertiesFunc		getPhysicalDeviceMemoryProperties;
+GetDeviceProcAddrFunc						getDeviceProcAddr;
+CreateDeviceFunc							createDevice;
+EnumerateDeviceExtensionPropertiesFunc		enumerateDeviceExtensionProperties;
+EnumerateDeviceLayerPropertiesFunc			enumerateDeviceLayerProperties;
diff --git a/external/vulkancts/framework/vulkan/vkMemUtil.cpp b/external/vulkancts/framework/vulkan/vkMemUtil.cpp
new file mode 100644
index 0000000..9eb3f02
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkMemUtil.cpp
@@ -0,0 +1,252 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Memory management utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkMemUtil.hpp"
+#include "vkStrUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "deInt32.h"
+
+#include <sstream>
+
+namespace vk
+{
+
+using de::UniquePtr;
+using de::MovePtr;
+
+namespace
+{
+
+class HostPtr
+{
+public:
+								HostPtr		(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
+								~HostPtr	(void);
+
+	void*						get			(void) const { return m_ptr; }
+
+private:
+	const DeviceInterface&		m_vkd;
+	const VkDevice				m_device;
+	const VkDeviceMemory		m_memory;
+	void* const					m_ptr;
+};
+
+void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
+{
+	void* hostPtr = DE_NULL;
+	VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
+	TCU_CHECK(hostPtr);
+	return hostPtr;
+}
+
+HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
+	: m_vkd		(vkd)
+	, m_device	(device)
+	, m_memory	(memory)
+	, m_ptr		(mapMemory(vkd, device, memory, offset, size, flags))
+{
+}
+
+HostPtr::~HostPtr (void)
+{
+	m_vkd.unmapMemory(m_device, m_memory);
+}
+
+deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
+{
+	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
+	{
+		if ((allowedMemTypeBits & (1u << memoryTypeNdx)) != 0 &&
+			requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
+			return memoryTypeNdx;
+	}
+
+	TCU_THROW(NotSupportedError, "No compatible memory type found");
+}
+
+bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
+{
+	DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
+	return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
+}
+
+} // anonymous
+
+// Allocation
+
+Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
+	: m_memory	(memory)
+	, m_offset	(offset)
+	, m_hostPtr	(hostPtr)
+{
+}
+
+Allocation::~Allocation (void)
+{
+}
+
+// MemoryRequirement
+
+const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
+const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
+const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
+const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
+
+bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
+{
+	// sanity check
+	if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
+		DE_FATAL("Coherent memory must be host-visible");
+	if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
+		DE_FATAL("Lazily allocated memory cannot be mappable");
+
+	// host-visible
+	if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
+		return false;
+
+	// coherent
+	if ((m_flags & FLAG_COHERENT) && (heapFlags & VK_MEMORY_PROPERTY_HOST_NON_COHERENT_BIT))
+		return false;
+
+	// lazy
+	if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
+		return false;
+
+	return true;
+}
+
+MemoryRequirement::MemoryRequirement (deUint32 flags)
+	: m_flags(flags)
+{
+}
+
+// SimpleAllocator
+
+class SimpleAllocation : public Allocation
+{
+public:
+									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
+	virtual							~SimpleAllocation	(void);
+
+private:
+	const Unique<VkDeviceMemory>	m_memHolder;
+	const UniquePtr<HostPtr>		m_hostPtr;
+};
+
+SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
+	: Allocation	(*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
+	, m_memHolder	(mem)
+	, m_hostPtr		(hostPtr)
+{
+}
+
+SimpleAllocation::~SimpleAllocation (void)
+{
+}
+
+SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
+	: m_vk		(vk)
+	, m_device	(device)
+	, m_memProps(deviceMemProps)
+{
+}
+
+MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocInfo& allocInfo, VkDeviceSize alignment)
+{
+	DE_UNREF(alignment);
+
+	Move<VkDeviceMemory>	mem		= allocMemory(m_vk, m_device, &allocInfo);
+	MovePtr<HostPtr>		hostPtr;
+
+	if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
+		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
+
+	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
+}
+
+MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
+{
+	const deUint32			memoryTypeNdx	= selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
+	const VkMemoryAllocInfo	allocInfo		=
+	{
+		VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,	//	VkStructureType			sType;
+		DE_NULL,								//	const void*				pNext;
+		memReqs.size,							//	VkDeviceSize			allocationSize;
+		memoryTypeNdx,							//	deUint32				memoryTypeIndex;
+	};
+
+	Move<VkDeviceMemory>	mem				= allocMemory(m_vk, m_device, &allocInfo);
+	MovePtr<HostPtr>		hostPtr;
+
+	if (requirement & MemoryRequirement::HostVisible)
+	{
+		DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
+		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
+	}
+
+	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
+}
+
+void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
+{
+	const VkMappedMemoryRange	range	=
+	{
+		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+		DE_NULL,
+		memory,
+		offset,
+		size
+	};
+
+	VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
+}
+
+void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
+{
+	const VkMappedMemoryRange	range	=
+	{
+		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+		DE_NULL,
+		memory,
+		offset,
+		size
+	};
+
+	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkMemUtil.hpp b/external/vulkancts/framework/vulkan/vkMemUtil.hpp
new file mode 100644
index 0000000..b6fd48a
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkMemUtil.hpp
@@ -0,0 +1,152 @@
+#ifndef _VKMEMUTIL_HPP
+#define _VKMEMUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Memory management utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "deUniquePtr.hpp"
+
+namespace vk
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Memory allocation interface
+ *
+ * Allocation represents block of device memory and is allocated by
+ * Allocator implementation. Test code should use Allocator for allocating
+ * memory, unless there is a reason not to (for example testing vkAllocMemory).
+ *
+ * Allocation doesn't necessarily correspond to a whole VkDeviceMemory, but
+ * instead it may represent sub-allocation. Thus whenever VkDeviceMemory
+ * (getMemory()) managed by Allocation is passed to Vulkan API calls,
+ * offset given by getOffset() must be used.
+ *
+ * If host-visible memory was requested, host pointer to the memory can
+ * be queried with getHostPtr(). No offset is needed when accessing host
+ * pointer, i.e. the pointer is already adjusted in case of sub-allocation.
+ *
+ * Memory mappings are managed solely by Allocation, i.e. unmapping or
+ * re-mapping VkDeviceMemory owned by Allocation is not allowed.
+ *//*--------------------------------------------------------------------*/
+class Allocation
+{
+public:
+	virtual					~Allocation	(void);
+
+	//! Get VkDeviceMemory backing this allocation
+	VkDeviceMemory			getMemory	(void) const { return m_memory;							}
+
+	//! Get offset in VkDeviceMemory for this allocation
+	VkDeviceSize			getOffset	(void) const { return m_offset;							}
+
+	//! Get host pointer for this allocation. Only available for host-visible allocations
+	void*					getHostPtr	(void) const { DE_ASSERT(m_hostPtr); return m_hostPtr;	}
+
+protected:
+							Allocation	(VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr);
+
+private:
+	const VkDeviceMemory	m_memory;
+	const VkDeviceSize		m_offset;
+	void* const				m_hostPtr;
+};
+
+//! Memory allocation requirements
+class MemoryRequirement
+{
+public:
+	static const MemoryRequirement	Any;
+	static const MemoryRequirement	HostVisible;
+	static const MemoryRequirement	Coherent;
+	static const MemoryRequirement	LazilyAllocated;
+
+	inline MemoryRequirement		operator|			(MemoryRequirement requirement) const
+	{
+		return MemoryRequirement(m_flags | requirement.m_flags);
+	}
+
+	inline MemoryRequirement		operator&			(MemoryRequirement requirement) const
+	{
+		return MemoryRequirement(m_flags & requirement.m_flags);
+	}
+
+	bool							matchesHeap			(VkMemoryPropertyFlags heapFlags) const;
+
+	inline operator					bool				(void) const { return m_flags != 0u; }
+
+private:
+	explicit						MemoryRequirement	(deUint32 flags);
+
+	const deUint32					m_flags;
+
+	enum Flags
+	{
+		FLAG_HOST_VISIBLE		= 1u << 0u,
+		FLAG_COHERENT			= 1u << 1u,
+		FLAG_LAZY_ALLOCATION	= 1u << 2u,
+	};
+};
+
+//! Memory allocator interface
+class Allocator
+{
+public:
+									Allocator	(void) {}
+	virtual							~Allocator	(void) {}
+
+	virtual de::MovePtr<Allocation>	allocate	(const VkMemoryAllocInfo& allocInfo, VkDeviceSize alignment) = 0;
+	virtual de::MovePtr<Allocation>	allocate	(const VkMemoryRequirements& memRequirements, MemoryRequirement requirement) = 0;
+};
+
+//! Allocator that backs every allocation with its own VkDeviceMemory
+class SimpleAllocator : public Allocator
+{
+public:
+											SimpleAllocator	(const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps);
+
+	de::MovePtr<Allocation>					allocate		(const VkMemoryAllocInfo& allocInfo, VkDeviceSize alignment);
+	de::MovePtr<Allocation>					allocate		(const VkMemoryRequirements& memRequirements, MemoryRequirement requirement);
+
+private:
+	const DeviceInterface&					m_vk;
+	const VkDevice							m_device;
+	const VkPhysicalDeviceMemoryProperties	m_memProps;
+};
+
+void	flushMappedMemoryRange		(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size);
+void	invalidateMappedMemoryRange	(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size);
+
+} // vk
+
+#endif // _VKMEMUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkNullDriver.cpp b/external/vulkancts/framework/vulkan/vkNullDriver.cpp
new file mode 100644
index 0000000..726600a
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkNullDriver.cpp
@@ -0,0 +1,342 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Null (dummy) Vulkan implementation.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkNullDriver.hpp"
+#include "vkPlatform.hpp"
+#include "tcuFunctionLibrary.hpp"
+#include "deMemory.h"
+
+#include <stdexcept>
+
+namespace vk
+{
+
+namespace
+{
+
+#define VK_NULL_RETURN(STMT)					\
+	do {										\
+		try {									\
+			STMT;								\
+			return VK_SUCCESS;					\
+		} catch (const std::bad_alloc&) {		\
+			return VK_ERROR_OUT_OF_HOST_MEMORY;	\
+		} catch (VkResult res) {				\
+			return res;							\
+		}										\
+	} while (deGetFalse())
+
+// \todo [2015-07-14 pyry] Check FUNC type by checkedCastToPtr<T>() or similar
+#define VK_NULL_FUNC_ENTRY(NAME, FUNC)	{ #NAME, (deFunctionPtr)FUNC }
+
+#define VK_NULL_DEFINE_DEVICE_OBJ(NAME)				\
+struct NAME											\
+{													\
+	NAME (VkDevice, const Vk##NAME##CreateInfo*) {}	\
+}
+
+class Instance
+{
+public:
+										Instance		(const VkInstanceCreateInfo* instanceInfo);
+										~Instance		(void) {}
+
+	PFN_vkVoidFunction					getProcAddr		(const char* name) const { return (PFN_vkVoidFunction)m_functions.getFunction(name); }
+
+private:
+	const tcu::StaticFunctionLibrary	m_functions;
+};
+
+class Device
+{
+public:
+										Device			(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* deviceInfo);
+										~Device			(void) {}
+
+	PFN_vkVoidFunction					getProcAddr		(const char* name) const { return (PFN_vkVoidFunction)m_functions.getFunction(name); }
+
+private:
+	const tcu::StaticFunctionLibrary	m_functions;
+};
+
+class DescriptorSet
+{
+public:
+	DescriptorSet (VkDevice, VkDescriptorPool, VkDescriptorSetUsage, VkDescriptorSetLayout) {}
+};
+
+class Pipeline
+{
+public:
+	Pipeline (VkDevice, const VkGraphicsPipelineCreateInfo*) {}
+	Pipeline (VkDevice, const VkComputePipelineCreateInfo*) {}
+};
+
+class DeviceMemory
+{
+public:
+						DeviceMemory	(VkDevice, const VkMemoryAllocInfo* pAllocInfo)
+							: m_memory(deMalloc((size_t)pAllocInfo->allocationSize))
+						{
+							if (!m_memory)
+								throw std::bad_alloc();
+						}
+						~DeviceMemory	(void)
+						{
+							deFree(m_memory);
+						}
+
+	void*				getPtr			(void) const { return m_memory; }
+
+private:
+	void* const			m_memory;
+};
+
+class Buffer
+{
+public:
+						Buffer		(VkDevice, const VkBufferCreateInfo* pCreateInfo)
+							: m_size(pCreateInfo->size)
+						{}
+
+	VkDeviceSize		getSize		(void) const { return m_size;	}
+
+private:
+	const VkDeviceSize	m_size;
+};
+
+VK_NULL_DEFINE_DEVICE_OBJ(CmdBuffer);
+VK_NULL_DEFINE_DEVICE_OBJ(Fence);
+VK_NULL_DEFINE_DEVICE_OBJ(Image);
+VK_NULL_DEFINE_DEVICE_OBJ(Semaphore);
+VK_NULL_DEFINE_DEVICE_OBJ(Event);
+VK_NULL_DEFINE_DEVICE_OBJ(QueryPool);
+VK_NULL_DEFINE_DEVICE_OBJ(BufferView);
+VK_NULL_DEFINE_DEVICE_OBJ(ImageView);
+VK_NULL_DEFINE_DEVICE_OBJ(ShaderModule);
+VK_NULL_DEFINE_DEVICE_OBJ(Shader);
+VK_NULL_DEFINE_DEVICE_OBJ(PipelineCache);
+VK_NULL_DEFINE_DEVICE_OBJ(PipelineLayout);
+VK_NULL_DEFINE_DEVICE_OBJ(RenderPass);
+VK_NULL_DEFINE_DEVICE_OBJ(DescriptorSetLayout);
+VK_NULL_DEFINE_DEVICE_OBJ(Sampler);
+VK_NULL_DEFINE_DEVICE_OBJ(Framebuffer);
+VK_NULL_DEFINE_DEVICE_OBJ(CmdPool);
+VK_NULL_DEFINE_DEVICE_OBJ(DescriptorPool);
+
+extern "C"
+{
+
+PFN_vkVoidFunction getInstanceProcAddr (VkInstance instance, const char* pName)
+{
+	return reinterpret_cast<Instance*>(instance)->getProcAddr(pName);
+}
+
+PFN_vkVoidFunction getDeviceProcAddr (VkDevice device, const char* pName)
+{
+	return reinterpret_cast<Device*>(device)->getProcAddr(pName);
+}
+
+VkResult createGraphicsPipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines)
+{
+	for (deUint32 ndx = 0; ndx < count; ndx++)
+		pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
+	return VK_SUCCESS;
+}
+
+VkResult createComputePipelines (VkDevice device, VkPipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines)
+{
+	for (deUint32 ndx = 0; ndx < count; ndx++)
+		pPipelines[ndx] = VkPipeline((deUint64)(deUintptr)new Pipeline(device, pCreateInfos+ndx));
+	return VK_SUCCESS;
+}
+
+VkResult enumeratePhysicalDevices (VkInstance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pDevices)
+{
+	if (pDevices && *pPhysicalDeviceCount >= 1u)
+		*pDevices = reinterpret_cast<VkPhysicalDevice>((void*)(deUintptr)1u);
+
+	*pPhysicalDeviceCount = 1;
+
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceProperties (VkPhysicalDevice, VkPhysicalDeviceProperties* props)
+{
+	deMemset(props, 0, sizeof(VkPhysicalDeviceProperties));
+
+	props->apiVersion		= VK_API_VERSION;
+	props->driverVersion	= 1u;
+	props->deviceType		= VK_PHYSICAL_DEVICE_TYPE_OTHER;
+
+	deMemcpy(props->deviceName, "null", 5);
+
+	// \todo [2015-09-25 pyry] Fill in reasonable limits
+
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceQueueFamilyProperties (VkPhysicalDevice, deUint32* count, VkQueueFamilyProperties* props)
+{
+	if (props && *count >= 1u)
+	{
+		deMemset(props, 0, sizeof(VkQueueFamilyProperties));
+
+		props->queueCount			= 1u;
+		props->queueFlags			= VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT|VK_QUEUE_DMA_BIT;
+		props->supportsTimestamps	= DE_TRUE;
+	}
+
+	*count = 1u;
+
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceMemoryProperties (VkPhysicalDevice, VkPhysicalDeviceMemoryProperties* props)
+{
+	deMemset(props, 0, sizeof(VkPhysicalDeviceMemoryProperties));
+
+	props->memoryTypeCount				= 1u;
+	props->memoryTypes[0].heapIndex		= 0u;
+	props->memoryTypes[0].propertyFlags	= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+	props->memoryHeapCount				= 1u;
+	props->memoryHeaps[0].size			= 1ull << 31;
+	props->memoryHeaps[0].flags			= VK_MEMORY_HEAP_HOST_LOCAL_BIT;
+
+	return VK_SUCCESS;
+}
+
+VkResult getBufferMemoryRequirements (VkDevice, VkBuffer bufferHandle, VkMemoryRequirements* requirements)
+{
+	const Buffer*	buffer	= reinterpret_cast<Buffer*>(bufferHandle.getInternal());
+
+	requirements->memoryTypeBits	= 1u;
+	requirements->size				= buffer->getSize();
+	requirements->alignment			= (VkDeviceSize)1u;
+
+	return VK_SUCCESS;
+}
+
+VkResult getImageMemoryRequirements (VkDevice, VkImage, VkMemoryRequirements* requirements)
+{
+	requirements->memoryTypeBits	= 1u;
+	requirements->size				= 4u;
+	requirements->alignment			= 4u;
+
+	return VK_SUCCESS;
+}
+
+VkResult mapMemory (VkDevice, VkDeviceMemory memHandle, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)
+{
+	const DeviceMemory*	memory	= reinterpret_cast<DeviceMemory*>(memHandle.getInternal());
+
+	DE_UNREF(size);
+	DE_UNREF(flags);
+
+	*ppData = (deUint8*)memory->getPtr() + offset;
+
+	return VK_SUCCESS;
+}
+
+VkResult allocDescriptorSets (VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, deUint32 count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets, deUint32* pCount)
+{
+	for (deUint32 ndx = 0; ndx < count; ++ndx)
+	{
+		try
+		{
+			pDescriptorSets[ndx] = VkDescriptorSet((deUint64)(deUintptr)new DescriptorSet(device, descriptorPool, setUsage, pSetLayouts[ndx]));
+		}
+		catch (const std::bad_alloc&)
+		{
+			*pCount = ndx;
+			return VK_ERROR_OUT_OF_HOST_MEMORY;
+		}
+		catch (VkResult res)
+		{
+			*pCount = ndx;
+			return res;
+		}
+	}
+
+	*pCount = count;
+	return VK_SUCCESS;
+}
+
+void freeDescriptorSets (VkDevice, VkDescriptorPool, deUint32 count, const VkDescriptorSet* pDescriptorSets)
+{
+	for (deUint32 ndx = 0; ndx < count; ++ndx)
+	{
+		// \note: delete cannot fail
+		delete reinterpret_cast<DescriptorSet*>((deUintptr)pDescriptorSets[ndx].getInternal());
+	}
+}
+
+#include "vkNullDriverImpl.inl"
+
+} // extern "C"
+
+Instance::Instance (const VkInstanceCreateInfo*)
+	: m_functions(s_instanceFunctions, DE_LENGTH_OF_ARRAY(s_instanceFunctions))
+{
+}
+
+Device::Device (VkPhysicalDevice, const VkDeviceCreateInfo*)
+	: m_functions(s_deviceFunctions, DE_LENGTH_OF_ARRAY(s_deviceFunctions))
+{
+}
+
+class NullDriverLibrary : public Library
+{
+public:
+								NullDriverLibrary (void)
+									: m_library	(s_platformFunctions, DE_LENGTH_OF_ARRAY(s_platformFunctions))
+									, m_driver	(m_library)
+								{}
+
+	const PlatformInterface&	getPlatformInterface	(void) const { return m_driver;	}
+
+private:
+	const tcu::StaticFunctionLibrary	m_library;
+	const PlatformDriver				m_driver;
+};
+
+} // anonymous
+
+Library* createNullDriver (void)
+{
+	return new NullDriverLibrary();
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkNullDriver.hpp b/external/vulkancts/framework/vulkan/vkNullDriver.hpp
new file mode 100644
index 0000000..3d6460d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkNullDriver.hpp
@@ -0,0 +1,48 @@
+#ifndef _VKNULLDRIVER_HPP
+#define _VKNULLDRIVER_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Null (dummy) Vulkan implementation.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+namespace vk
+{
+
+class Library;
+
+Library*	createNullDriver	(void);
+
+} // vk
+
+#endif // _VKNULLDRIVER_HPP
diff --git a/external/vulkancts/framework/vulkan/vkNullDriverImpl.inl b/external/vulkancts/framework/vulkan/vkNullDriverImpl.inl
new file mode 100644
index 0000000..cdce08b
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkNullDriverImpl.inl
@@ -0,0 +1,1133 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+VkResult createInstance (const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance)
+{
+	VK_NULL_RETURN(*pInstance = reinterpret_cast<VkInstance>(new Instance(pCreateInfo)));
+}
+
+VkResult createDevice (VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
+{
+	VK_NULL_RETURN(*pDevice = reinterpret_cast<VkDevice>(new Device(physicalDevice, pCreateInfo)));
+}
+
+VkResult allocMemory (VkDevice device, const VkMemoryAllocInfo* pAllocInfo, VkDeviceMemory* pMem)
+{
+	VK_NULL_RETURN(*pMem = VkDeviceMemory((deUint64)(deUintptr)new DeviceMemory(device, pAllocInfo)));
+}
+
+VkResult createFence (VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence)
+{
+	VK_NULL_RETURN(*pFence = VkFence((deUint64)(deUintptr)new Fence(device, pCreateInfo)));
+}
+
+VkResult createSemaphore (VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore)
+{
+	VK_NULL_RETURN(*pSemaphore = VkSemaphore((deUint64)(deUintptr)new Semaphore(device, pCreateInfo)));
+}
+
+VkResult createEvent (VkDevice device, const VkEventCreateInfo* pCreateInfo, VkEvent* pEvent)
+{
+	VK_NULL_RETURN(*pEvent = VkEvent((deUint64)(deUintptr)new Event(device, pCreateInfo)));
+}
+
+VkResult createQueryPool (VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, VkQueryPool* pQueryPool)
+{
+	VK_NULL_RETURN(*pQueryPool = VkQueryPool((deUint64)(deUintptr)new QueryPool(device, pCreateInfo)));
+}
+
+VkResult createBuffer (VkDevice device, const VkBufferCreateInfo* pCreateInfo, VkBuffer* pBuffer)
+{
+	VK_NULL_RETURN(*pBuffer = VkBuffer((deUint64)(deUintptr)new Buffer(device, pCreateInfo)));
+}
+
+VkResult createBufferView (VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, VkBufferView* pView)
+{
+	VK_NULL_RETURN(*pView = VkBufferView((deUint64)(deUintptr)new BufferView(device, pCreateInfo)));
+}
+
+VkResult createImage (VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage)
+{
+	VK_NULL_RETURN(*pImage = VkImage((deUint64)(deUintptr)new Image(device, pCreateInfo)));
+}
+
+VkResult createImageView (VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView)
+{
+	VK_NULL_RETURN(*pView = VkImageView((deUint64)(deUintptr)new ImageView(device, pCreateInfo)));
+}
+
+VkResult createShaderModule (VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule)
+{
+	VK_NULL_RETURN(*pShaderModule = VkShaderModule((deUint64)(deUintptr)new ShaderModule(device, pCreateInfo)));
+}
+
+VkResult createShader (VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader)
+{
+	VK_NULL_RETURN(*pShader = VkShader((deUint64)(deUintptr)new Shader(device, pCreateInfo)));
+}
+
+VkResult createPipelineCache (VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache)
+{
+	VK_NULL_RETURN(*pPipelineCache = VkPipelineCache((deUint64)(deUintptr)new PipelineCache(device, pCreateInfo)));
+}
+
+VkResult createPipelineLayout (VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout)
+{
+	VK_NULL_RETURN(*pPipelineLayout = VkPipelineLayout((deUint64)(deUintptr)new PipelineLayout(device, pCreateInfo)));
+}
+
+VkResult createSampler (VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler)
+{
+	VK_NULL_RETURN(*pSampler = VkSampler((deUint64)(deUintptr)new Sampler(device, pCreateInfo)));
+}
+
+VkResult createDescriptorSetLayout (VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout)
+{
+	VK_NULL_RETURN(*pSetLayout = VkDescriptorSetLayout((deUint64)(deUintptr)new DescriptorSetLayout(device, pCreateInfo)));
+}
+
+VkResult createDescriptorPool (VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorPool* pDescriptorPool)
+{
+	VK_NULL_RETURN(*pDescriptorPool = VkDescriptorPool((deUint64)(deUintptr)new DescriptorPool(device, pCreateInfo)));
+}
+
+VkResult createFramebuffer (VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, VkFramebuffer* pFramebuffer)
+{
+	VK_NULL_RETURN(*pFramebuffer = VkFramebuffer((deUint64)(deUintptr)new Framebuffer(device, pCreateInfo)));
+}
+
+VkResult createRenderPass (VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass)
+{
+	VK_NULL_RETURN(*pRenderPass = VkRenderPass((deUint64)(deUintptr)new RenderPass(device, pCreateInfo)));
+}
+
+VkResult createCommandPool (VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo, VkCmdPool* pCmdPool)
+{
+	VK_NULL_RETURN(*pCmdPool = VkCmdPool((deUint64)(deUintptr)new CmdPool(device, pCreateInfo)));
+}
+
+VkResult createCommandBuffer (VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, VkCmdBuffer* pCmdBuffer)
+{
+	VK_NULL_RETURN(*pCmdBuffer = reinterpret_cast<VkCmdBuffer>(new CmdBuffer(device, pCreateInfo)));
+}
+
+void destroyInstance (VkInstance instance)
+{
+	delete reinterpret_cast<Instance*>(instance);
+}
+
+void destroyDevice (VkDevice device)
+{
+	delete reinterpret_cast<Device*>(device);
+}
+
+void freeMemory (VkDevice device, VkDeviceMemory mem)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<DeviceMemory*>((deUintptr)mem.getInternal());
+}
+
+void destroyFence (VkDevice device, VkFence fence)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Fence*>((deUintptr)fence.getInternal());
+}
+
+void destroySemaphore (VkDevice device, VkSemaphore semaphore)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Semaphore*>((deUintptr)semaphore.getInternal());
+}
+
+void destroyEvent (VkDevice device, VkEvent event)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Event*>((deUintptr)event.getInternal());
+}
+
+void destroyQueryPool (VkDevice device, VkQueryPool queryPool)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<QueryPool*>((deUintptr)queryPool.getInternal());
+}
+
+void destroyBuffer (VkDevice device, VkBuffer buffer)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Buffer*>((deUintptr)buffer.getInternal());
+}
+
+void destroyBufferView (VkDevice device, VkBufferView bufferView)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<BufferView*>((deUintptr)bufferView.getInternal());
+}
+
+void destroyImage (VkDevice device, VkImage image)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Image*>((deUintptr)image.getInternal());
+}
+
+void destroyImageView (VkDevice device, VkImageView imageView)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<ImageView*>((deUintptr)imageView.getInternal());
+}
+
+void destroyShaderModule (VkDevice device, VkShaderModule shaderModule)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<ShaderModule*>((deUintptr)shaderModule.getInternal());
+}
+
+void destroyShader (VkDevice device, VkShader shader)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Shader*>((deUintptr)shader.getInternal());
+}
+
+void destroyPipelineCache (VkDevice device, VkPipelineCache pipelineCache)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<PipelineCache*>((deUintptr)pipelineCache.getInternal());
+}
+
+void destroyPipeline (VkDevice device, VkPipeline pipeline)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Pipeline*>((deUintptr)pipeline.getInternal());
+}
+
+void destroyPipelineLayout (VkDevice device, VkPipelineLayout pipelineLayout)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<PipelineLayout*>((deUintptr)pipelineLayout.getInternal());
+}
+
+void destroySampler (VkDevice device, VkSampler sampler)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Sampler*>((deUintptr)sampler.getInternal());
+}
+
+void destroyDescriptorSetLayout (VkDevice device, VkDescriptorSetLayout descriptorSetLayout)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<DescriptorSetLayout*>((deUintptr)descriptorSetLayout.getInternal());
+}
+
+void destroyDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<DescriptorPool*>((deUintptr)descriptorPool.getInternal());
+}
+
+void destroyFramebuffer (VkDevice device, VkFramebuffer framebuffer)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<Framebuffer*>((deUintptr)framebuffer.getInternal());
+}
+
+void destroyRenderPass (VkDevice device, VkRenderPass renderPass)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<RenderPass*>((deUintptr)renderPass.getInternal());
+}
+
+void destroyCommandPool (VkDevice device, VkCmdPool cmdPool)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<CmdPool*>((deUintptr)cmdPool.getInternal());
+}
+
+void destroyCommandBuffer (VkDevice device, VkCmdBuffer commandBuffer)
+{
+	DE_UNREF(device);
+	delete reinterpret_cast<CmdBuffer*>(commandBuffer);
+}
+
+VkResult getPhysicalDeviceFeatures (VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(pFeatures);
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(format);
+	DE_UNREF(pFormatProperties);
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceImageFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(format);
+	DE_UNREF(type);
+	DE_UNREF(tiling);
+	DE_UNREF(usage);
+	DE_UNREF(flags);
+	DE_UNREF(pImageFormatProperties);
+	return VK_SUCCESS;
+}
+
+VkResult enumerateInstanceExtensionProperties (const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties)
+{
+	DE_UNREF(pLayerName);
+	DE_UNREF(pCount);
+	DE_UNREF(pProperties);
+	return VK_SUCCESS;
+}
+
+VkResult enumerateDeviceExtensionProperties (VkPhysicalDevice physicalDevice, const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(pLayerName);
+	DE_UNREF(pCount);
+	DE_UNREF(pProperties);
+	return VK_SUCCESS;
+}
+
+VkResult enumerateInstanceLayerProperties (deUint32* pCount, VkLayerProperties* pProperties)
+{
+	DE_UNREF(pCount);
+	DE_UNREF(pProperties);
+	return VK_SUCCESS;
+}
+
+VkResult enumerateDeviceLayerProperties (VkPhysicalDevice physicalDevice, deUint32* pCount, VkLayerProperties* pProperties)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(pCount);
+	DE_UNREF(pProperties);
+	return VK_SUCCESS;
+}
+
+VkResult getDeviceQueue (VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex, VkQueue* pQueue)
+{
+	DE_UNREF(device);
+	DE_UNREF(queueFamilyIndex);
+	DE_UNREF(queueIndex);
+	DE_UNREF(pQueue);
+	return VK_SUCCESS;
+}
+
+VkResult queueSubmit (VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence)
+{
+	DE_UNREF(queue);
+	DE_UNREF(cmdBufferCount);
+	DE_UNREF(pCmdBuffers);
+	DE_UNREF(fence);
+	return VK_SUCCESS;
+}
+
+VkResult queueWaitIdle (VkQueue queue)
+{
+	DE_UNREF(queue);
+	return VK_SUCCESS;
+}
+
+VkResult deviceWaitIdle (VkDevice device)
+{
+	DE_UNREF(device);
+	return VK_SUCCESS;
+}
+
+void unmapMemory (VkDevice device, VkDeviceMemory mem)
+{
+	DE_UNREF(device);
+	DE_UNREF(mem);
+}
+
+VkResult flushMappedMemoryRanges (VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges)
+{
+	DE_UNREF(device);
+	DE_UNREF(memRangeCount);
+	DE_UNREF(pMemRanges);
+	return VK_SUCCESS;
+}
+
+VkResult invalidateMappedMemoryRanges (VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges)
+{
+	DE_UNREF(device);
+	DE_UNREF(memRangeCount);
+	DE_UNREF(pMemRanges);
+	return VK_SUCCESS;
+}
+
+VkResult getDeviceMemoryCommitment (VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes)
+{
+	DE_UNREF(device);
+	DE_UNREF(memory);
+	DE_UNREF(pCommittedMemoryInBytes);
+	return VK_SUCCESS;
+}
+
+VkResult bindBufferMemory (VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset)
+{
+	DE_UNREF(device);
+	DE_UNREF(buffer);
+	DE_UNREF(mem);
+	DE_UNREF(memOffset);
+	return VK_SUCCESS;
+}
+
+VkResult bindImageMemory (VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset)
+{
+	DE_UNREF(device);
+	DE_UNREF(image);
+	DE_UNREF(mem);
+	DE_UNREF(memOffset);
+	return VK_SUCCESS;
+}
+
+VkResult getImageSparseMemoryRequirements (VkDevice device, VkImage image, deUint32* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements)
+{
+	DE_UNREF(device);
+	DE_UNREF(image);
+	DE_UNREF(pNumRequirements);
+	DE_UNREF(pSparseMemoryRequirements);
+	return VK_SUCCESS;
+}
+
+VkResult getPhysicalDeviceSparseImageFormatProperties (VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, deUint32 samples, VkImageUsageFlags usage, VkImageTiling tiling, deUint32* pNumProperties, VkSparseImageFormatProperties* pProperties)
+{
+	DE_UNREF(physicalDevice);
+	DE_UNREF(format);
+	DE_UNREF(type);
+	DE_UNREF(samples);
+	DE_UNREF(usage);
+	DE_UNREF(tiling);
+	DE_UNREF(pNumProperties);
+	DE_UNREF(pProperties);
+	return VK_SUCCESS;
+}
+
+VkResult queueBindSparseBufferMemory (VkQueue queue, VkBuffer buffer, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo)
+{
+	DE_UNREF(queue);
+	DE_UNREF(buffer);
+	DE_UNREF(numBindings);
+	DE_UNREF(pBindInfo);
+	return VK_SUCCESS;
+}
+
+VkResult queueBindSparseImageOpaqueMemory (VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo)
+{
+	DE_UNREF(queue);
+	DE_UNREF(image);
+	DE_UNREF(numBindings);
+	DE_UNREF(pBindInfo);
+	return VK_SUCCESS;
+}
+
+VkResult queueBindSparseImageMemory (VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseImageMemoryBindInfo* pBindInfo)
+{
+	DE_UNREF(queue);
+	DE_UNREF(image);
+	DE_UNREF(numBindings);
+	DE_UNREF(pBindInfo);
+	return VK_SUCCESS;
+}
+
+VkResult resetFences (VkDevice device, deUint32 fenceCount, const VkFence* pFences)
+{
+	DE_UNREF(device);
+	DE_UNREF(fenceCount);
+	DE_UNREF(pFences);
+	return VK_SUCCESS;
+}
+
+VkResult getFenceStatus (VkDevice device, VkFence fence)
+{
+	DE_UNREF(device);
+	DE_UNREF(fence);
+	return VK_SUCCESS;
+}
+
+VkResult waitForFences (VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout)
+{
+	DE_UNREF(device);
+	DE_UNREF(fenceCount);
+	DE_UNREF(pFences);
+	DE_UNREF(waitAll);
+	DE_UNREF(timeout);
+	return VK_SUCCESS;
+}
+
+VkResult queueSignalSemaphore (VkQueue queue, VkSemaphore semaphore)
+{
+	DE_UNREF(queue);
+	DE_UNREF(semaphore);
+	return VK_SUCCESS;
+}
+
+VkResult queueWaitSemaphore (VkQueue queue, VkSemaphore semaphore)
+{
+	DE_UNREF(queue);
+	DE_UNREF(semaphore);
+	return VK_SUCCESS;
+}
+
+VkResult getEventStatus (VkDevice device, VkEvent event)
+{
+	DE_UNREF(device);
+	DE_UNREF(event);
+	return VK_SUCCESS;
+}
+
+VkResult setEvent (VkDevice device, VkEvent event)
+{
+	DE_UNREF(device);
+	DE_UNREF(event);
+	return VK_SUCCESS;
+}
+
+VkResult resetEvent (VkDevice device, VkEvent event)
+{
+	DE_UNREF(device);
+	DE_UNREF(event);
+	return VK_SUCCESS;
+}
+
+VkResult getQueryPoolResults (VkDevice device, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, deUintptr* pDataSize, void* pData, VkQueryResultFlags flags)
+{
+	DE_UNREF(device);
+	DE_UNREF(queryPool);
+	DE_UNREF(startQuery);
+	DE_UNREF(queryCount);
+	DE_UNREF(pDataSize);
+	DE_UNREF(pData);
+	DE_UNREF(flags);
+	return VK_SUCCESS;
+}
+
+VkResult getImageSubresourceLayout (VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout)
+{
+	DE_UNREF(device);
+	DE_UNREF(image);
+	DE_UNREF(pSubresource);
+	DE_UNREF(pLayout);
+	return VK_SUCCESS;
+}
+
+deUintptr getPipelineCacheSize (VkDevice device, VkPipelineCache pipelineCache)
+{
+	DE_UNREF(device);
+	DE_UNREF(pipelineCache);
+	return VK_SUCCESS;
+}
+
+VkResult getPipelineCacheData (VkDevice device, VkPipelineCache pipelineCache, void* pData)
+{
+	DE_UNREF(device);
+	DE_UNREF(pipelineCache);
+	DE_UNREF(pData);
+	return VK_SUCCESS;
+}
+
+VkResult mergePipelineCaches (VkDevice device, VkPipelineCache destCache, deUint32 srcCacheCount, const VkPipelineCache* pSrcCaches)
+{
+	DE_UNREF(device);
+	DE_UNREF(destCache);
+	DE_UNREF(srcCacheCount);
+	DE_UNREF(pSrcCaches);
+	return VK_SUCCESS;
+}
+
+VkResult resetDescriptorPool (VkDevice device, VkDescriptorPool descriptorPool)
+{
+	DE_UNREF(device);
+	DE_UNREF(descriptorPool);
+	return VK_SUCCESS;
+}
+
+void updateDescriptorSets (VkDevice device, deUint32 writeCount, const VkWriteDescriptorSet* pDescriptorWrites, deUint32 copyCount, const VkCopyDescriptorSet* pDescriptorCopies)
+{
+	DE_UNREF(device);
+	DE_UNREF(writeCount);
+	DE_UNREF(pDescriptorWrites);
+	DE_UNREF(copyCount);
+	DE_UNREF(pDescriptorCopies);
+}
+
+VkResult getRenderAreaGranularity (VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity)
+{
+	DE_UNREF(device);
+	DE_UNREF(renderPass);
+	DE_UNREF(pGranularity);
+	return VK_SUCCESS;
+}
+
+VkResult resetCommandPool (VkDevice device, VkCmdPool cmdPool, VkCmdPoolResetFlags flags)
+{
+	DE_UNREF(device);
+	DE_UNREF(cmdPool);
+	DE_UNREF(flags);
+	return VK_SUCCESS;
+}
+
+VkResult beginCommandBuffer (VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(pBeginInfo);
+	return VK_SUCCESS;
+}
+
+VkResult endCommandBuffer (VkCmdBuffer cmdBuffer)
+{
+	DE_UNREF(cmdBuffer);
+	return VK_SUCCESS;
+}
+
+VkResult resetCommandBuffer (VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(flags);
+	return VK_SUCCESS;
+}
+
+void cmdBindPipeline (VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(pipelineBindPoint);
+	DE_UNREF(pipeline);
+}
+
+void cmdSetViewport (VkCmdBuffer cmdBuffer, deUint32 viewportCount, const VkViewport* pViewports)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(viewportCount);
+	DE_UNREF(pViewports);
+}
+
+void cmdSetScissor (VkCmdBuffer cmdBuffer, deUint32 scissorCount, const VkRect2D* pScissors)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(scissorCount);
+	DE_UNREF(pScissors);
+}
+
+void cmdSetLineWidth (VkCmdBuffer cmdBuffer, float lineWidth)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(lineWidth);
+}
+
+void cmdSetDepthBias (VkCmdBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(depthBias);
+	DE_UNREF(depthBiasClamp);
+	DE_UNREF(slopeScaledDepthBias);
+}
+
+void cmdSetBlendConstants (VkCmdBuffer cmdBuffer, const float blendConst[4])
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(blendConst);
+}
+
+void cmdSetDepthBounds (VkCmdBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(minDepthBounds);
+	DE_UNREF(maxDepthBounds);
+}
+
+void cmdSetStencilCompareMask (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilCompareMask)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(faceMask);
+	DE_UNREF(stencilCompareMask);
+}
+
+void cmdSetStencilWriteMask (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilWriteMask)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(faceMask);
+	DE_UNREF(stencilWriteMask);
+}
+
+void cmdSetStencilReference (VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilReference)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(faceMask);
+	DE_UNREF(stencilReference);
+}
+
+void cmdBindDescriptorSets (VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, deUint32 firstSet, deUint32 setCount, const VkDescriptorSet* pDescriptorSets, deUint32 dynamicOffsetCount, const deUint32* pDynamicOffsets)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(pipelineBindPoint);
+	DE_UNREF(layout);
+	DE_UNREF(firstSet);
+	DE_UNREF(setCount);
+	DE_UNREF(pDescriptorSets);
+	DE_UNREF(dynamicOffsetCount);
+	DE_UNREF(pDynamicOffsets);
+}
+
+void cmdBindIndexBuffer (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(buffer);
+	DE_UNREF(offset);
+	DE_UNREF(indexType);
+}
+
+void cmdBindVertexBuffers (VkCmdBuffer cmdBuffer, deUint32 startBinding, deUint32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(startBinding);
+	DE_UNREF(bindingCount);
+	DE_UNREF(pBuffers);
+	DE_UNREF(pOffsets);
+}
+
+void cmdDraw (VkCmdBuffer cmdBuffer, deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(vertexCount);
+	DE_UNREF(instanceCount);
+	DE_UNREF(firstVertex);
+	DE_UNREF(firstInstance);
+}
+
+void cmdDrawIndexed (VkCmdBuffer cmdBuffer, deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(indexCount);
+	DE_UNREF(instanceCount);
+	DE_UNREF(firstIndex);
+	DE_UNREF(vertexOffset);
+	DE_UNREF(firstInstance);
+}
+
+void cmdDrawIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(buffer);
+	DE_UNREF(offset);
+	DE_UNREF(count);
+	DE_UNREF(stride);
+}
+
+void cmdDrawIndexedIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(buffer);
+	DE_UNREF(offset);
+	DE_UNREF(count);
+	DE_UNREF(stride);
+}
+
+void cmdDispatch (VkCmdBuffer cmdBuffer, deUint32 x, deUint32 y, deUint32 z)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(x);
+	DE_UNREF(y);
+	DE_UNREF(z);
+}
+
+void cmdDispatchIndirect (VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(buffer);
+	DE_UNREF(offset);
+}
+
+void cmdCopyBuffer (VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, deUint32 regionCount, const VkBufferCopy* pRegions)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcBuffer);
+	DE_UNREF(destBuffer);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+}
+
+void cmdCopyImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageCopy* pRegions)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcImage);
+	DE_UNREF(srcImageLayout);
+	DE_UNREF(destImage);
+	DE_UNREF(destImageLayout);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+}
+
+void cmdBlitImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageBlit* pRegions, VkTexFilter filter)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcImage);
+	DE_UNREF(srcImageLayout);
+	DE_UNREF(destImage);
+	DE_UNREF(destImageLayout);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+	DE_UNREF(filter);
+}
+
+void cmdCopyBufferToImage (VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkBufferImageCopy* pRegions)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcBuffer);
+	DE_UNREF(destImage);
+	DE_UNREF(destImageLayout);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+}
+
+void cmdCopyImageToBuffer (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, deUint32 regionCount, const VkBufferImageCopy* pRegions)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcImage);
+	DE_UNREF(srcImageLayout);
+	DE_UNREF(destBuffer);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+}
+
+void cmdUpdateBuffer (VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const deUint32* pData)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(destBuffer);
+	DE_UNREF(destOffset);
+	DE_UNREF(dataSize);
+	DE_UNREF(pData);
+}
+
+void cmdFillBuffer (VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, deUint32 data)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(destBuffer);
+	DE_UNREF(destOffset);
+	DE_UNREF(fillSize);
+	DE_UNREF(data);
+}
+
+void cmdClearColorImage (VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rangeCount, const VkImageSubresourceRange* pRanges)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(image);
+	DE_UNREF(imageLayout);
+	DE_UNREF(pColor);
+	DE_UNREF(rangeCount);
+	DE_UNREF(pRanges);
+}
+
+void cmdClearDepthStencilImage (VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rangeCount, const VkImageSubresourceRange* pRanges)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(image);
+	DE_UNREF(imageLayout);
+	DE_UNREF(pDepthStencil);
+	DE_UNREF(rangeCount);
+	DE_UNREF(pRanges);
+}
+
+void cmdClearColorAttachment (VkCmdBuffer cmdBuffer, deUint32 colorAttachment, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rectCount, const VkRect3D* pRects)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(colorAttachment);
+	DE_UNREF(imageLayout);
+	DE_UNREF(pColor);
+	DE_UNREF(rectCount);
+	DE_UNREF(pRects);
+}
+
+void cmdClearDepthStencilAttachment (VkCmdBuffer cmdBuffer, VkImageAspectFlags aspectMask, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rectCount, const VkRect3D* pRects)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(aspectMask);
+	DE_UNREF(imageLayout);
+	DE_UNREF(pDepthStencil);
+	DE_UNREF(rectCount);
+	DE_UNREF(pRects);
+}
+
+void cmdResolveImage (VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageResolve* pRegions)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcImage);
+	DE_UNREF(srcImageLayout);
+	DE_UNREF(destImage);
+	DE_UNREF(destImageLayout);
+	DE_UNREF(regionCount);
+	DE_UNREF(pRegions);
+}
+
+void cmdSetEvent (VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(event);
+	DE_UNREF(stageMask);
+}
+
+void cmdResetEvent (VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(event);
+	DE_UNREF(stageMask);
+}
+
+void cmdWaitEvents (VkCmdBuffer cmdBuffer, deUint32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, deUint32 memBarrierCount, const void* const* ppMemBarriers)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(eventCount);
+	DE_UNREF(pEvents);
+	DE_UNREF(srcStageMask);
+	DE_UNREF(destStageMask);
+	DE_UNREF(memBarrierCount);
+	DE_UNREF(ppMemBarriers);
+}
+
+void cmdPipelineBarrier (VkCmdBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, VkBool32 byRegion, deUint32 memBarrierCount, const void* const* ppMemBarriers)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(srcStageMask);
+	DE_UNREF(destStageMask);
+	DE_UNREF(byRegion);
+	DE_UNREF(memBarrierCount);
+	DE_UNREF(ppMemBarriers);
+}
+
+void cmdBeginQuery (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot, VkQueryControlFlags flags)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(queryPool);
+	DE_UNREF(slot);
+	DE_UNREF(flags);
+}
+
+void cmdEndQuery (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(queryPool);
+	DE_UNREF(slot);
+}
+
+void cmdResetQueryPool (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(queryPool);
+	DE_UNREF(startQuery);
+	DE_UNREF(queryCount);
+}
+
+void cmdWriteTimestamp (VkCmdBuffer cmdBuffer, VkTimestampType timestampType, VkBuffer destBuffer, VkDeviceSize destOffset)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(timestampType);
+	DE_UNREF(destBuffer);
+	DE_UNREF(destOffset);
+}
+
+void cmdCopyQueryPoolResults (VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(queryPool);
+	DE_UNREF(startQuery);
+	DE_UNREF(queryCount);
+	DE_UNREF(destBuffer);
+	DE_UNREF(destOffset);
+	DE_UNREF(destStride);
+	DE_UNREF(flags);
+}
+
+void cmdPushConstants (VkCmdBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, deUint32 start, deUint32 length, const void* values)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(layout);
+	DE_UNREF(stageFlags);
+	DE_UNREF(start);
+	DE_UNREF(length);
+	DE_UNREF(values);
+}
+
+void cmdBeginRenderPass (VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(pRenderPassBegin);
+	DE_UNREF(contents);
+}
+
+void cmdNextSubpass (VkCmdBuffer cmdBuffer, VkRenderPassContents contents)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(contents);
+}
+
+void cmdEndRenderPass (VkCmdBuffer cmdBuffer)
+{
+	DE_UNREF(cmdBuffer);
+}
+
+void cmdExecuteCommands (VkCmdBuffer cmdBuffer, deUint32 cmdBuffersCount, const VkCmdBuffer* pCmdBuffers)
+{
+	DE_UNREF(cmdBuffer);
+	DE_UNREF(cmdBuffersCount);
+	DE_UNREF(pCmdBuffers);
+}
+
+static const tcu::StaticFunctionLibrary::Entry s_platformFunctions[] =
+{
+	VK_NULL_FUNC_ENTRY(vkCreateInstance,						createInstance),
+	VK_NULL_FUNC_ENTRY(vkGetInstanceProcAddr,					getInstanceProcAddr),
+	VK_NULL_FUNC_ENTRY(vkEnumerateInstanceExtensionProperties,	enumerateInstanceExtensionProperties),
+	VK_NULL_FUNC_ENTRY(vkEnumerateInstanceLayerProperties,		enumerateInstanceLayerProperties),
+};
+
+static const tcu::StaticFunctionLibrary::Entry s_instanceFunctions[] =
+{
+	VK_NULL_FUNC_ENTRY(vkDestroyInstance,							destroyInstance),
+	VK_NULL_FUNC_ENTRY(vkEnumeratePhysicalDevices,					enumeratePhysicalDevices),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceFeatures,					getPhysicalDeviceFeatures),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceFormatProperties,			getPhysicalDeviceFormatProperties),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceImageFormatProperties,	getPhysicalDeviceImageFormatProperties),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceProperties,				getPhysicalDeviceProperties),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceQueueFamilyProperties,	getPhysicalDeviceQueueFamilyProperties),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceMemoryProperties,			getPhysicalDeviceMemoryProperties),
+	VK_NULL_FUNC_ENTRY(vkGetDeviceProcAddr,							getDeviceProcAddr),
+	VK_NULL_FUNC_ENTRY(vkCreateDevice,								createDevice),
+	VK_NULL_FUNC_ENTRY(vkEnumerateDeviceExtensionProperties,		enumerateDeviceExtensionProperties),
+	VK_NULL_FUNC_ENTRY(vkEnumerateDeviceLayerProperties,			enumerateDeviceLayerProperties),
+};
+
+static const tcu::StaticFunctionLibrary::Entry s_deviceFunctions[] =
+{
+	VK_NULL_FUNC_ENTRY(vkDestroyDevice,									destroyDevice),
+	VK_NULL_FUNC_ENTRY(vkGetDeviceQueue,								getDeviceQueue),
+	VK_NULL_FUNC_ENTRY(vkQueueSubmit,									queueSubmit),
+	VK_NULL_FUNC_ENTRY(vkQueueWaitIdle,									queueWaitIdle),
+	VK_NULL_FUNC_ENTRY(vkDeviceWaitIdle,								deviceWaitIdle),
+	VK_NULL_FUNC_ENTRY(vkAllocMemory,									allocMemory),
+	VK_NULL_FUNC_ENTRY(vkFreeMemory,									freeMemory),
+	VK_NULL_FUNC_ENTRY(vkMapMemory,										mapMemory),
+	VK_NULL_FUNC_ENTRY(vkUnmapMemory,									unmapMemory),
+	VK_NULL_FUNC_ENTRY(vkFlushMappedMemoryRanges,						flushMappedMemoryRanges),
+	VK_NULL_FUNC_ENTRY(vkInvalidateMappedMemoryRanges,					invalidateMappedMemoryRanges),
+	VK_NULL_FUNC_ENTRY(vkGetDeviceMemoryCommitment,						getDeviceMemoryCommitment),
+	VK_NULL_FUNC_ENTRY(vkBindBufferMemory,								bindBufferMemory),
+	VK_NULL_FUNC_ENTRY(vkBindImageMemory,								bindImageMemory),
+	VK_NULL_FUNC_ENTRY(vkGetBufferMemoryRequirements,					getBufferMemoryRequirements),
+	VK_NULL_FUNC_ENTRY(vkGetImageMemoryRequirements,					getImageMemoryRequirements),
+	VK_NULL_FUNC_ENTRY(vkGetImageSparseMemoryRequirements,				getImageSparseMemoryRequirements),
+	VK_NULL_FUNC_ENTRY(vkGetPhysicalDeviceSparseImageFormatProperties,	getPhysicalDeviceSparseImageFormatProperties),
+	VK_NULL_FUNC_ENTRY(vkQueueBindSparseBufferMemory,					queueBindSparseBufferMemory),
+	VK_NULL_FUNC_ENTRY(vkQueueBindSparseImageOpaqueMemory,				queueBindSparseImageOpaqueMemory),
+	VK_NULL_FUNC_ENTRY(vkQueueBindSparseImageMemory,					queueBindSparseImageMemory),
+	VK_NULL_FUNC_ENTRY(vkCreateFence,									createFence),
+	VK_NULL_FUNC_ENTRY(vkDestroyFence,									destroyFence),
+	VK_NULL_FUNC_ENTRY(vkResetFences,									resetFences),
+	VK_NULL_FUNC_ENTRY(vkGetFenceStatus,								getFenceStatus),
+	VK_NULL_FUNC_ENTRY(vkWaitForFences,									waitForFences),
+	VK_NULL_FUNC_ENTRY(vkCreateSemaphore,								createSemaphore),
+	VK_NULL_FUNC_ENTRY(vkDestroySemaphore,								destroySemaphore),
+	VK_NULL_FUNC_ENTRY(vkQueueSignalSemaphore,							queueSignalSemaphore),
+	VK_NULL_FUNC_ENTRY(vkQueueWaitSemaphore,							queueWaitSemaphore),
+	VK_NULL_FUNC_ENTRY(vkCreateEvent,									createEvent),
+	VK_NULL_FUNC_ENTRY(vkDestroyEvent,									destroyEvent),
+	VK_NULL_FUNC_ENTRY(vkGetEventStatus,								getEventStatus),
+	VK_NULL_FUNC_ENTRY(vkSetEvent,										setEvent),
+	VK_NULL_FUNC_ENTRY(vkResetEvent,									resetEvent),
+	VK_NULL_FUNC_ENTRY(vkCreateQueryPool,								createQueryPool),
+	VK_NULL_FUNC_ENTRY(vkDestroyQueryPool,								destroyQueryPool),
+	VK_NULL_FUNC_ENTRY(vkGetQueryPoolResults,							getQueryPoolResults),
+	VK_NULL_FUNC_ENTRY(vkCreateBuffer,									createBuffer),
+	VK_NULL_FUNC_ENTRY(vkDestroyBuffer,									destroyBuffer),
+	VK_NULL_FUNC_ENTRY(vkCreateBufferView,								createBufferView),
+	VK_NULL_FUNC_ENTRY(vkDestroyBufferView,								destroyBufferView),
+	VK_NULL_FUNC_ENTRY(vkCreateImage,									createImage),
+	VK_NULL_FUNC_ENTRY(vkDestroyImage,									destroyImage),
+	VK_NULL_FUNC_ENTRY(vkGetImageSubresourceLayout,						getImageSubresourceLayout),
+	VK_NULL_FUNC_ENTRY(vkCreateImageView,								createImageView),
+	VK_NULL_FUNC_ENTRY(vkDestroyImageView,								destroyImageView),
+	VK_NULL_FUNC_ENTRY(vkCreateShaderModule,							createShaderModule),
+	VK_NULL_FUNC_ENTRY(vkDestroyShaderModule,							destroyShaderModule),
+	VK_NULL_FUNC_ENTRY(vkCreateShader,									createShader),
+	VK_NULL_FUNC_ENTRY(vkDestroyShader,									destroyShader),
+	VK_NULL_FUNC_ENTRY(vkCreatePipelineCache,							createPipelineCache),
+	VK_NULL_FUNC_ENTRY(vkDestroyPipelineCache,							destroyPipelineCache),
+	VK_NULL_FUNC_ENTRY(vkGetPipelineCacheSize,							getPipelineCacheSize),
+	VK_NULL_FUNC_ENTRY(vkGetPipelineCacheData,							getPipelineCacheData),
+	VK_NULL_FUNC_ENTRY(vkMergePipelineCaches,							mergePipelineCaches),
+	VK_NULL_FUNC_ENTRY(vkCreateGraphicsPipelines,						createGraphicsPipelines),
+	VK_NULL_FUNC_ENTRY(vkCreateComputePipelines,						createComputePipelines),
+	VK_NULL_FUNC_ENTRY(vkDestroyPipeline,								destroyPipeline),
+	VK_NULL_FUNC_ENTRY(vkCreatePipelineLayout,							createPipelineLayout),
+	VK_NULL_FUNC_ENTRY(vkDestroyPipelineLayout,							destroyPipelineLayout),
+	VK_NULL_FUNC_ENTRY(vkCreateSampler,									createSampler),
+	VK_NULL_FUNC_ENTRY(vkDestroySampler,								destroySampler),
+	VK_NULL_FUNC_ENTRY(vkCreateDescriptorSetLayout,						createDescriptorSetLayout),
+	VK_NULL_FUNC_ENTRY(vkDestroyDescriptorSetLayout,					destroyDescriptorSetLayout),
+	VK_NULL_FUNC_ENTRY(vkCreateDescriptorPool,							createDescriptorPool),
+	VK_NULL_FUNC_ENTRY(vkDestroyDescriptorPool,							destroyDescriptorPool),
+	VK_NULL_FUNC_ENTRY(vkResetDescriptorPool,							resetDescriptorPool),
+	VK_NULL_FUNC_ENTRY(vkAllocDescriptorSets,							allocDescriptorSets),
+	VK_NULL_FUNC_ENTRY(vkFreeDescriptorSets,							freeDescriptorSets),
+	VK_NULL_FUNC_ENTRY(vkUpdateDescriptorSets,							updateDescriptorSets),
+	VK_NULL_FUNC_ENTRY(vkCreateFramebuffer,								createFramebuffer),
+	VK_NULL_FUNC_ENTRY(vkDestroyFramebuffer,							destroyFramebuffer),
+	VK_NULL_FUNC_ENTRY(vkCreateRenderPass,								createRenderPass),
+	VK_NULL_FUNC_ENTRY(vkDestroyRenderPass,								destroyRenderPass),
+	VK_NULL_FUNC_ENTRY(vkGetRenderAreaGranularity,						getRenderAreaGranularity),
+	VK_NULL_FUNC_ENTRY(vkCreateCommandPool,								createCommandPool),
+	VK_NULL_FUNC_ENTRY(vkDestroyCommandPool,							destroyCommandPool),
+	VK_NULL_FUNC_ENTRY(vkResetCommandPool,								resetCommandPool),
+	VK_NULL_FUNC_ENTRY(vkCreateCommandBuffer,							createCommandBuffer),
+	VK_NULL_FUNC_ENTRY(vkDestroyCommandBuffer,							destroyCommandBuffer),
+	VK_NULL_FUNC_ENTRY(vkBeginCommandBuffer,							beginCommandBuffer),
+	VK_NULL_FUNC_ENTRY(vkEndCommandBuffer,								endCommandBuffer),
+	VK_NULL_FUNC_ENTRY(vkResetCommandBuffer,							resetCommandBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdBindPipeline,								cmdBindPipeline),
+	VK_NULL_FUNC_ENTRY(vkCmdSetViewport,								cmdSetViewport),
+	VK_NULL_FUNC_ENTRY(vkCmdSetScissor,									cmdSetScissor),
+	VK_NULL_FUNC_ENTRY(vkCmdSetLineWidth,								cmdSetLineWidth),
+	VK_NULL_FUNC_ENTRY(vkCmdSetDepthBias,								cmdSetDepthBias),
+	VK_NULL_FUNC_ENTRY(vkCmdSetBlendConstants,							cmdSetBlendConstants),
+	VK_NULL_FUNC_ENTRY(vkCmdSetDepthBounds,								cmdSetDepthBounds),
+	VK_NULL_FUNC_ENTRY(vkCmdSetStencilCompareMask,						cmdSetStencilCompareMask),
+	VK_NULL_FUNC_ENTRY(vkCmdSetStencilWriteMask,						cmdSetStencilWriteMask),
+	VK_NULL_FUNC_ENTRY(vkCmdSetStencilReference,						cmdSetStencilReference),
+	VK_NULL_FUNC_ENTRY(vkCmdBindDescriptorSets,							cmdBindDescriptorSets),
+	VK_NULL_FUNC_ENTRY(vkCmdBindIndexBuffer,							cmdBindIndexBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdBindVertexBuffers,							cmdBindVertexBuffers),
+	VK_NULL_FUNC_ENTRY(vkCmdDraw,										cmdDraw),
+	VK_NULL_FUNC_ENTRY(vkCmdDrawIndexed,								cmdDrawIndexed),
+	VK_NULL_FUNC_ENTRY(vkCmdDrawIndirect,								cmdDrawIndirect),
+	VK_NULL_FUNC_ENTRY(vkCmdDrawIndexedIndirect,						cmdDrawIndexedIndirect),
+	VK_NULL_FUNC_ENTRY(vkCmdDispatch,									cmdDispatch),
+	VK_NULL_FUNC_ENTRY(vkCmdDispatchIndirect,							cmdDispatchIndirect),
+	VK_NULL_FUNC_ENTRY(vkCmdCopyBuffer,									cmdCopyBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdCopyImage,									cmdCopyImage),
+	VK_NULL_FUNC_ENTRY(vkCmdBlitImage,									cmdBlitImage),
+	VK_NULL_FUNC_ENTRY(vkCmdCopyBufferToImage,							cmdCopyBufferToImage),
+	VK_NULL_FUNC_ENTRY(vkCmdCopyImageToBuffer,							cmdCopyImageToBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdUpdateBuffer,								cmdUpdateBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdFillBuffer,									cmdFillBuffer),
+	VK_NULL_FUNC_ENTRY(vkCmdClearColorImage,							cmdClearColorImage),
+	VK_NULL_FUNC_ENTRY(vkCmdClearDepthStencilImage,						cmdClearDepthStencilImage),
+	VK_NULL_FUNC_ENTRY(vkCmdClearColorAttachment,						cmdClearColorAttachment),
+	VK_NULL_FUNC_ENTRY(vkCmdClearDepthStencilAttachment,				cmdClearDepthStencilAttachment),
+	VK_NULL_FUNC_ENTRY(vkCmdResolveImage,								cmdResolveImage),
+	VK_NULL_FUNC_ENTRY(vkCmdSetEvent,									cmdSetEvent),
+	VK_NULL_FUNC_ENTRY(vkCmdResetEvent,									cmdResetEvent),
+	VK_NULL_FUNC_ENTRY(vkCmdWaitEvents,									cmdWaitEvents),
+	VK_NULL_FUNC_ENTRY(vkCmdPipelineBarrier,							cmdPipelineBarrier),
+	VK_NULL_FUNC_ENTRY(vkCmdBeginQuery,									cmdBeginQuery),
+	VK_NULL_FUNC_ENTRY(vkCmdEndQuery,									cmdEndQuery),
+	VK_NULL_FUNC_ENTRY(vkCmdResetQueryPool,								cmdResetQueryPool),
+	VK_NULL_FUNC_ENTRY(vkCmdWriteTimestamp,								cmdWriteTimestamp),
+	VK_NULL_FUNC_ENTRY(vkCmdCopyQueryPoolResults,						cmdCopyQueryPoolResults),
+	VK_NULL_FUNC_ENTRY(vkCmdPushConstants,								cmdPushConstants),
+	VK_NULL_FUNC_ENTRY(vkCmdBeginRenderPass,							cmdBeginRenderPass),
+	VK_NULL_FUNC_ENTRY(vkCmdNextSubpass,								cmdNextSubpass),
+	VK_NULL_FUNC_ENTRY(vkCmdEndRenderPass,								cmdEndRenderPass),
+	VK_NULL_FUNC_ENTRY(vkCmdExecuteCommands,							cmdExecuteCommands),
+};
+
diff --git a/external/vulkancts/framework/vulkan/vkPlatform.cpp b/external/vulkancts/framework/vulkan/vkPlatform.cpp
new file mode 100644
index 0000000..12332f0
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPlatform.cpp
@@ -0,0 +1,78 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan platform abstraction.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkPlatform.hpp"
+#include "tcuFunctionLibrary.hpp"
+
+namespace vk
+{
+
+PlatformDriver::PlatformDriver (const tcu::FunctionLibrary& library)
+{
+#define GET_PROC_ADDR(NAME) library.getFunction(NAME)
+#include "vkInitPlatformFunctionPointers.inl"
+#undef GET_PROC_ADDR
+}
+
+PlatformDriver::~PlatformDriver (void)
+{
+}
+
+InstanceDriver::InstanceDriver (const PlatformInterface& platformInterface, VkInstance instance)
+{
+#define GET_PROC_ADDR(NAME) platformInterface.getInstanceProcAddr(instance, NAME)
+#include "vkInitInstanceFunctionPointers.inl"
+#undef GET_PROC_ADDR
+}
+
+InstanceDriver::~InstanceDriver (void)
+{
+}
+
+DeviceDriver::DeviceDriver (const InstanceInterface& instanceInterface, VkDevice device)
+{
+#define GET_PROC_ADDR(NAME) instanceInterface.getDeviceProcAddr(device, NAME)
+#include "vkInitDeviceFunctionPointers.inl"
+#undef GET_PROC_ADDR
+}
+
+DeviceDriver::~DeviceDriver (void)
+{
+}
+
+#include "vkPlatformDriverImpl.inl"
+#include "vkInstanceDriverImpl.inl"
+#include "vkDeviceDriverImpl.inl"
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkPlatform.hpp b/external/vulkancts/framework/vulkan/vkPlatform.hpp
new file mode 100644
index 0000000..06b1603
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPlatform.hpp
@@ -0,0 +1,122 @@
+#ifndef _VKPLATFORM_HPP
+#define _VKPLATFORM_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan platform abstraction.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+namespace tcu
+{
+class FunctionLibrary;
+}
+
+namespace vk
+{
+
+class Library
+{
+public:
+										Library					(void) {}
+	virtual								~Library				(void) {}
+
+	virtual const PlatformInterface&	getPlatformInterface	(void) const = 0;
+};
+
+class PlatformDriver : public PlatformInterface
+{
+public:
+				PlatformDriver	(const tcu::FunctionLibrary& library);
+				~PlatformDriver	(void);
+
+#include "vkConcretePlatformInterface.inl"
+
+protected:
+	struct Functions
+	{
+#include "vkPlatformFunctionPointers.inl"
+	};
+
+	Functions	m_vk;
+};
+
+class InstanceDriver : public InstanceInterface
+{
+public:
+				InstanceDriver	(const PlatformInterface& platformInterface, VkInstance instance);
+				~InstanceDriver	(void);
+
+#include "vkConcreteInstanceInterface.inl"
+
+protected:
+	struct Functions
+	{
+#include "vkInstanceFunctionPointers.inl"
+	};
+
+	Functions	m_vk;
+};
+
+class DeviceDriver : public DeviceInterface
+{
+public:
+				DeviceDriver	(const InstanceInterface& instanceInterface, VkDevice device);
+				~DeviceDriver	(void);
+
+#include "vkConcreteDeviceInterface.inl"
+
+protected:
+	struct Functions
+	{
+#include "vkDeviceFunctionPointers.inl"
+	};
+
+	Functions	m_vk;
+};
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Vulkan platform interface
+ *//*--------------------------------------------------------------------*/
+class Platform
+{
+public:
+						Platform		(void) {}
+						~Platform		(void) {}
+
+	// \todo [2015-01-05 pyry] Parametrize this to select for example debug library / interface?
+	virtual Library*	createLibrary	(void) const = 0;
+};
+
+} // vk
+
+#endif // _VKPLATFORM_HPP
diff --git a/external/vulkancts/framework/vulkan/vkPlatformDriverImpl.inl b/external/vulkancts/framework/vulkan/vkPlatformDriverImpl.inl
new file mode 100644
index 0000000..bfe062d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPlatformDriverImpl.inl
@@ -0,0 +1,23 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+
+VkResult PlatformDriver::createInstance (const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance) const
+{
+	return m_vk.createInstance(pCreateInfo, pInstance);
+}
+
+PFN_vkVoidFunction PlatformDriver::getInstanceProcAddr (VkInstance instance, const char* pName) const
+{
+	return m_vk.getInstanceProcAddr(instance, pName);
+}
+
+VkResult PlatformDriver::enumerateInstanceExtensionProperties (const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const
+{
+	return m_vk.enumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
+}
+
+VkResult PlatformDriver::enumerateInstanceLayerProperties (deUint32* pCount, VkLayerProperties* pProperties) const
+{
+	return m_vk.enumerateInstanceLayerProperties(pCount, pProperties);
+}
diff --git a/external/vulkancts/framework/vulkan/vkPlatformFunctionPointers.inl b/external/vulkancts/framework/vulkan/vkPlatformFunctionPointers.inl
new file mode 100644
index 0000000..60cea42
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPlatformFunctionPointers.inl
@@ -0,0 +1,7 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+CreateInstanceFunc							createInstance;
+GetInstanceProcAddrFunc						getInstanceProcAddr;
+EnumerateInstanceExtensionPropertiesFunc	enumerateInstanceExtensionProperties;
+EnumerateInstanceLayerPropertiesFunc		enumerateInstanceLayerProperties;
diff --git a/external/vulkancts/framework/vulkan/vkPrograms.cpp b/external/vulkancts/framework/vulkan/vkPrograms.cpp
new file mode 100644
index 0000000..4483885
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPrograms.cpp
@@ -0,0 +1,130 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Program utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkPrograms.hpp"
+#include "vkGlslToSpirV.hpp"
+#include "vkSpirVAsm.hpp"
+#include "vkRefUtil.hpp"
+
+#include "tcuTestLog.hpp"
+
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+using tcu::TestLog;
+
+// ProgramBinary
+
+ProgramBinary::ProgramBinary (ProgramFormat format, size_t binarySize, const deUint8* binary)
+	: m_format	(format)
+	, m_binary	(binary, binary+binarySize)
+{
+}
+
+// Utils
+
+ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo)
+{
+	if (binaryFormat == PROGRAM_FORMAT_SPIRV)
+	{
+		vector<deUint8> binary;
+		glslToSpirV(program, &binary, buildInfo);
+		return new ProgramBinary(binaryFormat, binary.size(), &binary[0]);
+	}
+	else
+		TCU_THROW(NotSupportedError, "Unsupported program format");
+}
+
+ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo)
+{
+	vector<deUint8> binary;
+	assembleSpirV(&program, &binary, buildInfo);
+	return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size(), &binary[0]);
+}
+
+Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags)
+{
+	if (binary.getFormat() == PROGRAM_FORMAT_SPIRV)
+	{
+		const struct VkShaderModuleCreateInfo		shaderModuleInfo	=
+		{
+			VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+			DE_NULL,
+			(deUintptr)binary.getSize(),
+			binary.getBinary(),
+			flags,
+		};
+
+		return createShaderModule(deviceInterface, device, &shaderModuleInfo);
+	}
+	else
+		TCU_THROW(NotSupportedError, "Unsupported program format");
+}
+
+glu::ShaderType getGluShaderType (VkShaderStage shaderStage)
+{
+	static const glu::ShaderType s_shaderTypes[] =
+	{
+		glu::SHADERTYPE_VERTEX,
+		glu::SHADERTYPE_TESSELLATION_CONTROL,
+		glu::SHADERTYPE_TESSELLATION_EVALUATION,
+		glu::SHADERTYPE_GEOMETRY,
+		glu::SHADERTYPE_FRAGMENT,
+		glu::SHADERTYPE_COMPUTE
+	};
+
+	return de::getSizedArrayElement<VK_SHADER_STAGE_LAST>(s_shaderTypes, shaderStage);
+}
+
+VkShaderStage getVkShaderStage (glu::ShaderType shaderType)
+{
+	static const VkShaderStage s_shaderStages[] =
+	{
+		VK_SHADER_STAGE_VERTEX,
+		VK_SHADER_STAGE_FRAGMENT,
+		VK_SHADER_STAGE_GEOMETRY,
+		VK_SHADER_STAGE_TESS_CONTROL,
+		VK_SHADER_STAGE_TESS_EVALUATION,
+		VK_SHADER_STAGE_COMPUTE
+	};
+
+	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType);
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkPrograms.hpp b/external/vulkancts/framework/vulkan/vkPrograms.hpp
new file mode 100644
index 0000000..356eb16
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkPrograms.hpp
@@ -0,0 +1,193 @@
+#ifndef _VKPROGRAMS_HPP
+#define _VKPROGRAMS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Program utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+#include "vkSpirVProgram.hpp"
+#include "gluShaderProgram.hpp"
+#include "deUniquePtr.hpp"
+#include "deSTLUtil.hpp"
+
+#include <vector>
+#include <map>
+
+namespace tcu
+{
+class TestLog;
+} // tcu
+
+namespace vk
+{
+
+enum ProgramFormat
+{
+	PROGRAM_FORMAT_SPIRV = 0,
+
+	PROGRAM_FORMAT_LAST
+};
+
+class ProgramBinary
+{
+public:
+								ProgramBinary	(ProgramFormat format, size_t binarySize, const deUint8* binary);
+
+	ProgramFormat				getFormat		(void) const { return m_format;										}
+	size_t						getSize			(void) const { return m_binary.size();								}
+	const deUint8*				getBinary		(void) const { return m_binary.empty() ? DE_NULL : &m_binary[0];	}
+
+private:
+	const ProgramFormat			m_format;
+	const std::vector<deUint8>	m_binary;
+};
+
+template<typename Program>
+class ProgramCollection
+{
+public:
+								ProgramCollection	(void);
+								~ProgramCollection	(void);
+
+	void						clear				(void);
+
+	Program&					add					(const std::string& name);
+	void						add					(const std::string& name, de::MovePtr<Program>& program);
+
+	bool						contains			(const std::string& name) const;
+	const Program&				get					(const std::string& name) const;
+
+	class Iterator
+	{
+	private:
+		typedef typename std::map<std::string, Program*>::const_iterator	IteratorImpl;
+
+	public:
+		explicit			Iterator	(const IteratorImpl& i) : m_impl(i) {}
+
+		Iterator&			operator++	(void)			{ ++m_impl; return *this;	}
+		const Program&		operator*	(void) const	{ return getProgram();		}
+
+		const std::string&	getName		(void) const	{ return m_impl->first;		}
+		const Program&		getProgram	(void) const	{ return *m_impl->second;	}
+
+		bool				operator==	(const Iterator& other) const	{ return m_impl == other.m_impl;	}
+		bool				operator!=	(const Iterator& other) const	{ return m_impl != other.m_impl;	}
+
+	private:
+
+		IteratorImpl	m_impl;
+	};
+
+	Iterator					begin				(void) const { return Iterator(m_programs.begin());	}
+	Iterator					end					(void) const { return Iterator(m_programs.end());	}
+
+private:
+	typedef std::map<std::string, Program*>	ProgramMap;
+
+	ProgramMap					m_programs;
+};
+
+template<typename Program>
+ProgramCollection<Program>::ProgramCollection (void)
+{
+}
+
+template<typename Program>
+ProgramCollection<Program>::~ProgramCollection (void)
+{
+	clear();
+}
+
+template<typename Program>
+void ProgramCollection<Program>::clear (void)
+{
+	for (typename ProgramMap::const_iterator i = m_programs.begin(); i != m_programs.end(); ++i)
+		delete i->second;
+	m_programs.clear();
+}
+
+template<typename Program>
+Program& ProgramCollection<Program>::add (const std::string& name)
+{
+	DE_ASSERT(!contains(name));
+	de::MovePtr<Program> prog = de::newMovePtr<Program>();
+	m_programs[name] = prog.get();
+	prog.release();
+	return *m_programs[name];
+}
+
+template<typename Program>
+void ProgramCollection<Program>::add (const std::string& name, de::MovePtr<Program>& program)
+{
+	DE_ASSERT(!contains(name));
+	m_programs[name] = program.get();
+	program.release();
+}
+
+template<typename Program>
+bool ProgramCollection<Program>::contains (const std::string& name) const
+{
+	return de::contains(m_programs, name);
+}
+
+template<typename Program>
+const Program& ProgramCollection<Program>::get (const std::string& name) const
+{
+	DE_ASSERT(contains(name));
+	return *m_programs.find(name)->second;
+}
+
+typedef vk::ProgramCollection<glu::ProgramSources>	GlslSourceCollection;
+typedef vk::ProgramCollection<vk::SpirVAsmSource>	SpirVAsmCollection;
+
+struct SourceCollections
+{
+	GlslSourceCollection	glslSources;
+	SpirVAsmCollection		spirvAsmSources;
+};
+
+typedef ProgramCollection<ProgramBinary>		BinaryCollection;
+
+// \todo [2015-03-13 pyry] Likely need BinaryBuilder abstraction for this
+ProgramBinary*			buildProgram		(const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo);
+ProgramBinary*			assembleProgram		(const vk::SpirVAsmSource& program, SpirVProgramInfo* buildInfo);
+Move<VkShaderModule>	createShaderModule	(const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags);
+
+glu::ShaderType			getGluShaderType	(VkShaderStage shaderStage);
+VkShaderStage			getVkShaderStage	(glu::ShaderType shaderType);
+
+} // vk
+
+#endif // _VKPROGRAMS_HPP
diff --git a/external/vulkancts/framework/vulkan/vkQueryUtil.cpp b/external/vulkancts/framework/vulkan/vkQueryUtil.cpp
new file mode 100644
index 0000000..5c903e6
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkQueryUtil.cpp
@@ -0,0 +1,172 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan query utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkQueryUtil.hpp"
+#include "deMemory.h"
+
+namespace vk
+{
+
+using std::vector;
+
+vector<VkPhysicalDevice> enumeratePhysicalDevices (const InstanceInterface& vk, VkInstance instance)
+{
+	deUint32					numDevices	= 0;
+	vector<VkPhysicalDevice>	devices;
+
+	VK_CHECK(vk.enumeratePhysicalDevices(instance, &numDevices, DE_NULL));
+
+	if (numDevices > 0)
+	{
+		devices.resize(numDevices);
+		VK_CHECK(vk.enumeratePhysicalDevices(instance, &numDevices, &devices[0]));
+
+		if ((size_t)numDevices != devices.size())
+			TCU_FAIL("Returned device count changed between queries");
+	}
+
+	return devices;
+}
+
+vector<VkQueueFamilyProperties> getPhysicalDeviceQueueFamilyProperties (const InstanceInterface& vk, VkPhysicalDevice physicalDevice)
+{
+	deUint32						numQueues	= 0;
+	vector<VkQueueFamilyProperties>	properties;
+
+	VK_CHECK(vk.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, DE_NULL));
+
+	if (numQueues > 0)
+	{
+		properties.resize(numQueues);
+		VK_CHECK(vk.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, &properties[0]));
+
+		if ((size_t)numQueues != properties.size())
+			TCU_FAIL("Returned queue family count changes between queries");
+	}
+
+	return properties;
+}
+
+VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties (const InstanceInterface& vk, VkPhysicalDevice physicalDevice)
+{
+	VkPhysicalDeviceMemoryProperties	properties;
+
+	deMemset(&properties, 0, sizeof(properties));
+
+	VK_CHECK(vk.getPhysicalDeviceMemoryProperties(physicalDevice, &properties));
+	return properties;
+}
+
+VkMemoryRequirements getBufferMemoryRequirements (const DeviceInterface& vk, VkDevice device, VkBuffer buffer)
+{
+	VkMemoryRequirements req;
+	VK_CHECK(vk.getBufferMemoryRequirements(device, buffer, &req));
+	return req;
+}
+VkMemoryRequirements getImageMemoryRequirements (const DeviceInterface& vk, VkDevice device, VkImage image)
+{
+	VkMemoryRequirements req;
+	VK_CHECK(vk.getImageMemoryRequirements(device, image, &req));
+	return req;
+}
+
+vector<VkLayerProperties> enumerateInstanceLayerProperties (const PlatformInterface& vkp)
+{
+	vector<VkLayerProperties>	properties;
+	deUint32					numLayers	= 0;
+
+	VK_CHECK(vkp.enumerateInstanceLayerProperties(&numLayers, DE_NULL));
+
+	if (numLayers > 0)
+	{
+		properties.resize(numLayers);
+		VK_CHECK(vkp.enumerateInstanceLayerProperties(&numLayers, &properties[0]));
+		TCU_CHECK((size_t)numLayers == properties.size());
+	}
+
+	return properties;
+}
+
+vector<VkExtensionProperties> enumerateInstanceExtensionProperties (const PlatformInterface& vkp, const char* layerName)
+{
+	vector<VkExtensionProperties>	properties;
+	deUint32						numExtensions	= 0;
+
+	VK_CHECK(vkp.enumerateInstanceExtensionProperties(layerName, &numExtensions, DE_NULL));
+
+	if (numExtensions > 0)
+	{
+		properties.resize(numExtensions);
+		VK_CHECK(vkp.enumerateInstanceExtensionProperties(layerName, &numExtensions, &properties[0]));
+		TCU_CHECK((size_t)numExtensions == properties.size());
+	}
+
+	return properties;
+}
+
+vector<VkLayerProperties> enumerateDeviceLayerProperties (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
+{
+	vector<VkLayerProperties>	properties;
+	deUint32					numLayers	= 0;
+
+	VK_CHECK(vki.enumerateDeviceLayerProperties(physicalDevice, &numLayers, DE_NULL));
+
+	if (numLayers > 0)
+	{
+		properties.resize(numLayers);
+		VK_CHECK(vki.enumerateDeviceLayerProperties(physicalDevice, &numLayers, &properties[0]));
+		TCU_CHECK((size_t)numLayers == properties.size());
+	}
+
+	return properties;
+}
+
+vector<VkExtensionProperties> enumerateDeviceExtensionProperties (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const char* layerName)
+{
+	vector<VkExtensionProperties>	properties;
+	deUint32						numExtensions	= 0;
+
+	VK_CHECK(vki.enumerateDeviceExtensionProperties(physicalDevice, layerName, &numExtensions, DE_NULL));
+
+	if (numExtensions > 0)
+	{
+		properties.resize(numExtensions);
+		VK_CHECK(vki.enumerateDeviceExtensionProperties(physicalDevice, layerName, &numExtensions, &properties[0]));
+		TCU_CHECK((size_t)numExtensions == properties.size());
+	}
+
+	return properties;
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkQueryUtil.hpp b/external/vulkancts/framework/vulkan/vkQueryUtil.hpp
new file mode 100644
index 0000000..b576a9d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkQueryUtil.hpp
@@ -0,0 +1,58 @@
+#ifndef _VKQUERYUTIL_HPP
+#define _VKQUERYUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan query utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+#include <vector>
+
+namespace vk
+{
+
+std::vector<VkPhysicalDevice>			enumeratePhysicalDevices				(const InstanceInterface& vk, VkInstance instance);
+std::vector<VkQueueFamilyProperties>	getPhysicalDeviceQueueFamilyProperties	(const InstanceInterface& vk, VkPhysicalDevice physicalDevice);
+VkPhysicalDeviceMemoryProperties		getPhysicalDeviceMemoryProperties		(const InstanceInterface& vk, VkPhysicalDevice physicalDevice);
+
+VkMemoryRequirements					getBufferMemoryRequirements				(const DeviceInterface& vk, VkDevice device, VkBuffer buffer);
+VkMemoryRequirements					getImageMemoryRequirements				(const DeviceInterface& vk, VkDevice device, VkImage image);
+
+std::vector<VkLayerProperties>			enumerateInstanceLayerProperties		(const PlatformInterface& vkp);
+std::vector<VkExtensionProperties>		enumerateInstanceExtensionProperties	(const PlatformInterface& vkp, const char* layerName);
+std::vector<VkLayerProperties>			enumerateDeviceLayerProperties			(const InstanceInterface& vki, VkPhysicalDevice physicalDevice);
+std::vector<VkExtensionProperties>		enumerateDeviceExtensionProperties		(const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const char* layerName);
+
+} // vk
+
+#endif // _VKQUERYUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkRef.cpp b/external/vulkancts/framework/vulkan/vkRef.cpp
new file mode 100644
index 0000000..5eb2764
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRef.cpp
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object reference holder.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkRef.hpp"
+
+DE_EMPTY_CPP_FILE
diff --git a/external/vulkancts/framework/vulkan/vkRef.hpp b/external/vulkancts/framework/vulkan/vkRef.hpp
new file mode 100644
index 0000000..3d6fa3c
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRef.hpp
@@ -0,0 +1,308 @@
+#ifndef _VKREF_HPP
+#define _VKREF_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object reference holder.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkStrUtil.hpp"
+#include "deMeta.hpp"
+
+#include <algorithm>
+
+namespace vk
+{
+
+namespace refdetails
+{
+
+using std::swap;
+
+template<typename T>
+struct Checked
+{
+	explicit inline		Checked		(T object_) : object(object_) {}
+
+	T					object;
+};
+
+//! Check that object is not null
+template<typename T>
+inline Checked<T> check (T object)
+{
+	if (!object)
+		throw tcu::TestError("Object check() failed", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
+	return Checked<T>(object);
+}
+
+//! Declare object as checked earlier
+template<typename T>
+inline Checked<T> notNull (T object)
+{
+	if (!object)
+		throw tcu::InternalError("Null object was given to notNull()", (std::string(getTypeName<T>()) + " = 0").c_str(), __FILE__, __LINE__);
+	return Checked<T>(object);
+}
+
+//! Allow null object
+template<typename T>
+inline Checked<T> allowNull (T object)
+{
+	return Checked<T>(object);
+}
+
+template<typename T>
+class Deleter
+{
+public:
+							Deleter		(const DeviceInterface& deviceIface, VkDevice device)
+								: m_deviceIface	(&deviceIface)
+								, m_device		(device)
+							{}
+							Deleter		(void)
+								: m_deviceIface	(DE_NULL)
+								, m_device		(DE_NULL)
+							{}
+
+	void					operator()	(T obj) const;
+
+private:
+	const DeviceInterface*	m_deviceIface;
+	VkDevice				m_device;
+};
+
+template<>
+class Deleter<VkInstance>
+{
+public:
+							Deleter		(const PlatformInterface& platformIface, VkInstance instance)
+								: m_destroyInstance((DestroyInstanceFunc)platformIface.getInstanceProcAddr(instance, "vkDestroyInstance"))
+							{}
+							Deleter		(void)
+								: m_destroyInstance((DestroyInstanceFunc)DE_NULL)
+							{}
+
+	void					operator()	(VkInstance obj) const { m_destroyInstance(obj); }
+
+private:
+	DestroyInstanceFunc		m_destroyInstance;
+};
+
+template<>
+class Deleter<VkDevice>
+{
+public:
+							Deleter		(const InstanceInterface& instanceIface, VkDevice device)
+								: m_destroyDevice((DestroyDeviceFunc)instanceIface.getDeviceProcAddr(device, "vkDestroyDevice"))
+							{}
+							Deleter		(void)
+								: m_destroyDevice((DestroyDeviceFunc)DE_NULL)
+							{}
+
+	void					operator()	(VkDevice obj) const { m_destroyDevice(obj); }
+
+private:
+	DestroyDeviceFunc		m_destroyDevice;
+};
+
+template<>
+class Deleter<VkDescriptorSet>
+{
+public:
+							Deleter		(const DeviceInterface& deviceIface, VkDevice device, VkDescriptorPool pool)
+								: m_deviceIface	(&deviceIface)
+								, m_device		(device)
+								, m_pool		(pool)
+							{}
+							Deleter		(void)
+								: m_deviceIface	(DE_NULL)
+								, m_device		(DE_NULL)
+								, m_pool		(DE_NULL)
+							{}
+
+	void					operator()	(VkDescriptorSet obj) const { m_deviceIface->freeDescriptorSets(m_device, m_pool, 1, &obj); }
+
+private:
+	const DeviceInterface*	m_deviceIface;
+	VkDevice				m_device;
+	VkDescriptorPool		m_pool;
+};
+
+template<typename T>
+struct RefData
+{
+				RefData		(T object_, Deleter<T> deleter_)
+								: object	(object_)
+								, deleter	(deleter_)
+				{}
+				RefData		(void)
+								: object	(0)
+				{}
+
+	T			object;
+	Deleter<T>	deleter;
+};
+
+template<typename T>
+class RefBase
+{
+public:
+						~RefBase	(void);
+
+	inline const T&		get			(void) const throw() { return m_data.object;	}
+	inline const T&		operator*	(void) const throw() { return get();			}
+	inline operator		bool		(void) const throw() { return !!get();			}
+
+protected:
+						RefBase		(RefData<T> data) : m_data(data)	{}
+
+	void				reset		(void);				//!< Release previous object, set to null.
+	RefData<T>			disown		(void) throw();		//!< Disown and return object (ownership transferred to caller).
+	void				assign		(RefData<T> data);	//!< Set new pointer, release previous pointer.
+
+private:
+	RefData<T>			m_data;
+};
+
+template<typename T>
+inline RefBase<T>::~RefBase (void)
+{
+	this->reset();
+}
+
+template<typename T>
+inline void RefBase<T>::reset (void)
+{
+	if (!!m_data.object)
+		m_data.deleter(m_data.object);
+
+	m_data = RefData<T>();
+}
+
+template<typename T>
+inline RefData<T> RefBase<T>::disown (void) throw()
+{
+	RefData<T> tmp;
+	swap(m_data, tmp);
+	return tmp;
+}
+
+template<typename T>
+inline void RefBase<T>::assign (RefData<T> data)
+{
+	this->reset();
+	m_data = data;
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Movable Vulkan object reference.
+ *
+ * Similar to de::MovePtr.
+ *//*--------------------------------------------------------------------*/
+template<typename T>
+class Move : public RefBase<T>
+{
+public:
+	template<typename U>
+				Move		(Checked<U> object, Deleter<U> deleter)
+								: RefBase<T>(RefData<T>(object.object, deleter))
+				{}
+
+				Move		(RefData<T> data)
+								: RefBase<T>(data)
+				{}
+				Move		(Move<T>& other)
+								: RefBase<T>(other.RefBase<T>::disown())
+				{}
+				Move		(void)
+								: RefBase<T>(RefData<T>())
+				{}
+
+	T			disown		(void) { return this->RefBase<T>::disown().object; }
+	Move<T>&	operator=	(Move<T>& other);
+	Move<T>&	operator=	(RefData<T> data);
+
+	operator	RefData<T>	(void) { return this->RefBase<T>::disown(); }
+};
+
+template<typename T>
+inline Move<T>& Move<T>::operator= (Move<T>& other)
+{
+	if (this != &other)
+		this->assign(other.RefBase<T>::disown());
+
+	return *this;
+}
+
+template<typename T>
+inline Move<T>& Move<T>::operator= (RefData<T> data)
+{
+	this->assign(data);
+	return *this;
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Unique Vulkan object reference.
+ *
+ * Similar to de::UniquePtr.
+ *//*--------------------------------------------------------------------*/
+template<typename T>
+class Unique : public RefBase<T>
+{
+public:
+	template<typename U>
+				Unique		(Checked<U> object, Deleter<U> deleter)
+								: RefBase<T>(RefData<T>(object.object, deleter))
+				{}
+
+				Unique		(RefData<T> data)
+								: RefBase<T>(data)
+				{}
+
+private:
+				Unique		(const Unique<T>&);
+	Unique<T>&	operator=	(const Unique<T>&);
+};
+
+} // refdetails
+
+using refdetails::Move;
+using refdetails::Unique;
+using refdetails::Deleter;
+using refdetails::check;
+using refdetails::notNull;
+using refdetails::allowNull;
+
+} // vk
+
+#endif // _VKREF_HPP
diff --git a/external/vulkancts/framework/vulkan/vkRefUtil.cpp b/external/vulkancts/framework/vulkan/vkRefUtil.cpp
new file mode 100644
index 0000000..696d18d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRefUtil.cpp
@@ -0,0 +1,65 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object reference holder utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkRefUtil.hpp"
+
+namespace vk
+{
+
+#include "vkRefUtilImpl.inl"
+
+Move<VkPipeline> createGraphicsPipeline (const DeviceInterface& vk, VkDevice device, VkPipelineCache pipelineCache, const VkGraphicsPipelineCreateInfo* pCreateInfo)
+{
+	VkPipeline object = 0;
+	VK_CHECK(vk.createGraphicsPipelines(device, pipelineCache, 1u, pCreateInfo, &object));
+	return Move<VkPipeline>(check<VkPipeline>(object), Deleter<VkPipeline>(vk, device));
+}
+
+Move<VkPipeline> createComputePipeline (const DeviceInterface& vk, VkDevice device, VkPipelineCache pipelineCache, const VkComputePipelineCreateInfo* pCreateInfo)
+{
+	VkPipeline object = 0;
+	VK_CHECK(vk.createComputePipelines(device, pipelineCache, 1u, pCreateInfo, &object));
+	return Move<VkPipeline>(check<VkPipeline>(object), Deleter<VkPipeline>(vk, device));
+}
+
+Move<VkDescriptorSet> allocDescriptorSet (const DeviceInterface& vk, VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, VkDescriptorSetLayout layout)
+{
+	VkDescriptorSet	descriptorSet	= 0;
+
+	VK_CHECK(vk.allocDescriptorSets(device, descriptorPool, setUsage, 1, &layout, &descriptorSet));
+
+	return Move<VkDescriptorSet>(check<VkDescriptorSet>(descriptorSet), Deleter<VkDescriptorSet>(vk, device, descriptorPool));
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkRefUtil.hpp b/external/vulkancts/framework/vulkan/vkRefUtil.hpp
new file mode 100644
index 0000000..7dedbd7
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRefUtil.hpp
@@ -0,0 +1,51 @@
+#ifndef _VKREFUTIL_HPP
+#define _VKREFUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan object reference holder utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+
+namespace vk
+{
+
+#include "vkRefUtil.inl"
+
+Move<VkPipeline>		createGraphicsPipeline	(const DeviceInterface& vk, VkDevice device, VkPipelineCache pipelineCache, const VkGraphicsPipelineCreateInfo* pCreateInfo);
+Move<VkPipeline>		createComputePipeline	(const DeviceInterface& vk, VkDevice device, VkPipelineCache pipelineCache, const VkComputePipelineCreateInfo* pCreateInfo);
+Move<VkDescriptorSet>	allocDescriptorSet		(const DeviceInterface& vk, VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, VkDescriptorSetLayout layout);
+
+} // vk
+
+#endif // _VKREFUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkRefUtil.inl b/external/vulkancts/framework/vulkan/vkRefUtil.inl
new file mode 100644
index 0000000..5afc84d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRefUtil.inl
@@ -0,0 +1,25 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+Move<VkInstance>			createInstance				(const PlatformInterface& vk, const VkInstanceCreateInfo* pCreateInfo);
+Move<VkDevice>				createDevice				(const InstanceInterface& vk, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo);
+Move<VkDeviceMemory>		allocMemory					(const DeviceInterface& vk, VkDevice device, const VkMemoryAllocInfo* pAllocInfo);
+Move<VkFence>				createFence					(const DeviceInterface& vk, VkDevice device, const VkFenceCreateInfo* pCreateInfo);
+Move<VkSemaphore>			createSemaphore				(const DeviceInterface& vk, VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo);
+Move<VkEvent>				createEvent					(const DeviceInterface& vk, VkDevice device, const VkEventCreateInfo* pCreateInfo);
+Move<VkQueryPool>			createQueryPool				(const DeviceInterface& vk, VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo);
+Move<VkBuffer>				createBuffer				(const DeviceInterface& vk, VkDevice device, const VkBufferCreateInfo* pCreateInfo);
+Move<VkBufferView>			createBufferView			(const DeviceInterface& vk, VkDevice device, const VkBufferViewCreateInfo* pCreateInfo);
+Move<VkImage>				createImage					(const DeviceInterface& vk, VkDevice device, const VkImageCreateInfo* pCreateInfo);
+Move<VkImageView>			createImageView				(const DeviceInterface& vk, VkDevice device, const VkImageViewCreateInfo* pCreateInfo);
+Move<VkShaderModule>		createShaderModule			(const DeviceInterface& vk, VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo);
+Move<VkShader>				createShader				(const DeviceInterface& vk, VkDevice device, const VkShaderCreateInfo* pCreateInfo);
+Move<VkPipelineCache>		createPipelineCache			(const DeviceInterface& vk, VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo);
+Move<VkPipelineLayout>		createPipelineLayout		(const DeviceInterface& vk, VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo);
+Move<VkSampler>				createSampler				(const DeviceInterface& vk, VkDevice device, const VkSamplerCreateInfo* pCreateInfo);
+Move<VkDescriptorSetLayout>	createDescriptorSetLayout	(const DeviceInterface& vk, VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo);
+Move<VkDescriptorPool>		createDescriptorPool		(const DeviceInterface& vk, VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo);
+Move<VkFramebuffer>			createFramebuffer			(const DeviceInterface& vk, VkDevice device, const VkFramebufferCreateInfo* pCreateInfo);
+Move<VkRenderPass>			createRenderPass			(const DeviceInterface& vk, VkDevice device, const VkRenderPassCreateInfo* pCreateInfo);
+Move<VkCmdPool>				createCommandPool			(const DeviceInterface& vk, VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo);
+Move<VkCmdBuffer>			createCommandBuffer			(const DeviceInterface& vk, VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo);
diff --git a/external/vulkancts/framework/vulkan/vkRefUtilImpl.inl b/external/vulkancts/framework/vulkan/vkRefUtilImpl.inl
new file mode 100644
index 0000000..d05f4be
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkRefUtilImpl.inl
@@ -0,0 +1,288 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+namespace refdetails
+{
+
+template<>
+void Deleter<VkDeviceMemory>::operator() (VkDeviceMemory obj) const
+{
+	m_deviceIface->freeMemory(m_device, obj);
+}
+
+template<>
+void Deleter<VkFence>::operator() (VkFence obj) const
+{
+	m_deviceIface->destroyFence(m_device, obj);
+}
+
+template<>
+void Deleter<VkSemaphore>::operator() (VkSemaphore obj) const
+{
+	m_deviceIface->destroySemaphore(m_device, obj);
+}
+
+template<>
+void Deleter<VkEvent>::operator() (VkEvent obj) const
+{
+	m_deviceIface->destroyEvent(m_device, obj);
+}
+
+template<>
+void Deleter<VkQueryPool>::operator() (VkQueryPool obj) const
+{
+	m_deviceIface->destroyQueryPool(m_device, obj);
+}
+
+template<>
+void Deleter<VkBuffer>::operator() (VkBuffer obj) const
+{
+	m_deviceIface->destroyBuffer(m_device, obj);
+}
+
+template<>
+void Deleter<VkBufferView>::operator() (VkBufferView obj) const
+{
+	m_deviceIface->destroyBufferView(m_device, obj);
+}
+
+template<>
+void Deleter<VkImage>::operator() (VkImage obj) const
+{
+	m_deviceIface->destroyImage(m_device, obj);
+}
+
+template<>
+void Deleter<VkImageView>::operator() (VkImageView obj) const
+{
+	m_deviceIface->destroyImageView(m_device, obj);
+}
+
+template<>
+void Deleter<VkShaderModule>::operator() (VkShaderModule obj) const
+{
+	m_deviceIface->destroyShaderModule(m_device, obj);
+}
+
+template<>
+void Deleter<VkShader>::operator() (VkShader obj) const
+{
+	m_deviceIface->destroyShader(m_device, obj);
+}
+
+template<>
+void Deleter<VkPipelineCache>::operator() (VkPipelineCache obj) const
+{
+	m_deviceIface->destroyPipelineCache(m_device, obj);
+}
+
+template<>
+void Deleter<VkPipeline>::operator() (VkPipeline obj) const
+{
+	m_deviceIface->destroyPipeline(m_device, obj);
+}
+
+template<>
+void Deleter<VkPipelineLayout>::operator() (VkPipelineLayout obj) const
+{
+	m_deviceIface->destroyPipelineLayout(m_device, obj);
+}
+
+template<>
+void Deleter<VkSampler>::operator() (VkSampler obj) const
+{
+	m_deviceIface->destroySampler(m_device, obj);
+}
+
+template<>
+void Deleter<VkDescriptorSetLayout>::operator() (VkDescriptorSetLayout obj) const
+{
+	m_deviceIface->destroyDescriptorSetLayout(m_device, obj);
+}
+
+template<>
+void Deleter<VkDescriptorPool>::operator() (VkDescriptorPool obj) const
+{
+	m_deviceIface->destroyDescriptorPool(m_device, obj);
+}
+
+template<>
+void Deleter<VkFramebuffer>::operator() (VkFramebuffer obj) const
+{
+	m_deviceIface->destroyFramebuffer(m_device, obj);
+}
+
+template<>
+void Deleter<VkRenderPass>::operator() (VkRenderPass obj) const
+{
+	m_deviceIface->destroyRenderPass(m_device, obj);
+}
+
+template<>
+void Deleter<VkCmdPool>::operator() (VkCmdPool obj) const
+{
+	m_deviceIface->destroyCommandPool(m_device, obj);
+}
+
+template<>
+void Deleter<VkCmdBuffer>::operator() (VkCmdBuffer obj) const
+{
+	m_deviceIface->destroyCommandBuffer(m_device, obj);
+}
+
+} // refdetails
+
+Move<VkInstance> createInstance (const PlatformInterface& vk, const VkInstanceCreateInfo* pCreateInfo)
+{
+	VkInstance object = 0;
+	VK_CHECK(vk.createInstance(pCreateInfo, &object));
+	return Move<VkInstance>(check<VkInstance>(object), Deleter<VkInstance>(vk, object));
+}
+
+Move<VkDevice> createDevice (const InstanceInterface& vk, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo)
+{
+	VkDevice object = 0;
+	VK_CHECK(vk.createDevice(physicalDevice, pCreateInfo, &object));
+	return Move<VkDevice>(check<VkDevice>(object), Deleter<VkDevice>(vk, object));
+}
+
+Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, const VkMemoryAllocInfo* pAllocInfo)
+{
+	VkDeviceMemory object = 0;
+	VK_CHECK(vk.allocMemory(device, pAllocInfo, &object));
+	return Move<VkDeviceMemory>(check<VkDeviceMemory>(object), Deleter<VkDeviceMemory>(vk, device));
+}
+
+Move<VkFence> createFence (const DeviceInterface& vk, VkDevice device, const VkFenceCreateInfo* pCreateInfo)
+{
+	VkFence object = 0;
+	VK_CHECK(vk.createFence(device, pCreateInfo, &object));
+	return Move<VkFence>(check<VkFence>(object), Deleter<VkFence>(vk, device));
+}
+
+Move<VkSemaphore> createSemaphore (const DeviceInterface& vk, VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo)
+{
+	VkSemaphore object = 0;
+	VK_CHECK(vk.createSemaphore(device, pCreateInfo, &object));
+	return Move<VkSemaphore>(check<VkSemaphore>(object), Deleter<VkSemaphore>(vk, device));
+}
+
+Move<VkEvent> createEvent (const DeviceInterface& vk, VkDevice device, const VkEventCreateInfo* pCreateInfo)
+{
+	VkEvent object = 0;
+	VK_CHECK(vk.createEvent(device, pCreateInfo, &object));
+	return Move<VkEvent>(check<VkEvent>(object), Deleter<VkEvent>(vk, device));
+}
+
+Move<VkQueryPool> createQueryPool (const DeviceInterface& vk, VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo)
+{
+	VkQueryPool object = 0;
+	VK_CHECK(vk.createQueryPool(device, pCreateInfo, &object));
+	return Move<VkQueryPool>(check<VkQueryPool>(object), Deleter<VkQueryPool>(vk, device));
+}
+
+Move<VkBuffer> createBuffer (const DeviceInterface& vk, VkDevice device, const VkBufferCreateInfo* pCreateInfo)
+{
+	VkBuffer object = 0;
+	VK_CHECK(vk.createBuffer(device, pCreateInfo, &object));
+	return Move<VkBuffer>(check<VkBuffer>(object), Deleter<VkBuffer>(vk, device));
+}
+
+Move<VkBufferView> createBufferView (const DeviceInterface& vk, VkDevice device, const VkBufferViewCreateInfo* pCreateInfo)
+{
+	VkBufferView object = 0;
+	VK_CHECK(vk.createBufferView(device, pCreateInfo, &object));
+	return Move<VkBufferView>(check<VkBufferView>(object), Deleter<VkBufferView>(vk, device));
+}
+
+Move<VkImage> createImage (const DeviceInterface& vk, VkDevice device, const VkImageCreateInfo* pCreateInfo)
+{
+	VkImage object = 0;
+	VK_CHECK(vk.createImage(device, pCreateInfo, &object));
+	return Move<VkImage>(check<VkImage>(object), Deleter<VkImage>(vk, device));
+}
+
+Move<VkImageView> createImageView (const DeviceInterface& vk, VkDevice device, const VkImageViewCreateInfo* pCreateInfo)
+{
+	VkImageView object = 0;
+	VK_CHECK(vk.createImageView(device, pCreateInfo, &object));
+	return Move<VkImageView>(check<VkImageView>(object), Deleter<VkImageView>(vk, device));
+}
+
+Move<VkShaderModule> createShaderModule (const DeviceInterface& vk, VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo)
+{
+	VkShaderModule object = 0;
+	VK_CHECK(vk.createShaderModule(device, pCreateInfo, &object));
+	return Move<VkShaderModule>(check<VkShaderModule>(object), Deleter<VkShaderModule>(vk, device));
+}
+
+Move<VkShader> createShader (const DeviceInterface& vk, VkDevice device, const VkShaderCreateInfo* pCreateInfo)
+{
+	VkShader object = 0;
+	VK_CHECK(vk.createShader(device, pCreateInfo, &object));
+	return Move<VkShader>(check<VkShader>(object), Deleter<VkShader>(vk, device));
+}
+
+Move<VkPipelineCache> createPipelineCache (const DeviceInterface& vk, VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo)
+{
+	VkPipelineCache object = 0;
+	VK_CHECK(vk.createPipelineCache(device, pCreateInfo, &object));
+	return Move<VkPipelineCache>(check<VkPipelineCache>(object), Deleter<VkPipelineCache>(vk, device));
+}
+
+Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vk, VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo)
+{
+	VkPipelineLayout object = 0;
+	VK_CHECK(vk.createPipelineLayout(device, pCreateInfo, &object));
+	return Move<VkPipelineLayout>(check<VkPipelineLayout>(object), Deleter<VkPipelineLayout>(vk, device));
+}
+
+Move<VkSampler> createSampler (const DeviceInterface& vk, VkDevice device, const VkSamplerCreateInfo* pCreateInfo)
+{
+	VkSampler object = 0;
+	VK_CHECK(vk.createSampler(device, pCreateInfo, &object));
+	return Move<VkSampler>(check<VkSampler>(object), Deleter<VkSampler>(vk, device));
+}
+
+Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vk, VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo)
+{
+	VkDescriptorSetLayout object = 0;
+	VK_CHECK(vk.createDescriptorSetLayout(device, pCreateInfo, &object));
+	return Move<VkDescriptorSetLayout>(check<VkDescriptorSetLayout>(object), Deleter<VkDescriptorSetLayout>(vk, device));
+}
+
+Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vk, VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo)
+{
+	VkDescriptorPool object = 0;
+	VK_CHECK(vk.createDescriptorPool(device, pCreateInfo, &object));
+	return Move<VkDescriptorPool>(check<VkDescriptorPool>(object), Deleter<VkDescriptorPool>(vk, device));
+}
+
+Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vk, VkDevice device, const VkFramebufferCreateInfo* pCreateInfo)
+{
+	VkFramebuffer object = 0;
+	VK_CHECK(vk.createFramebuffer(device, pCreateInfo, &object));
+	return Move<VkFramebuffer>(check<VkFramebuffer>(object), Deleter<VkFramebuffer>(vk, device));
+}
+
+Move<VkRenderPass> createRenderPass (const DeviceInterface& vk, VkDevice device, const VkRenderPassCreateInfo* pCreateInfo)
+{
+	VkRenderPass object = 0;
+	VK_CHECK(vk.createRenderPass(device, pCreateInfo, &object));
+	return Move<VkRenderPass>(check<VkRenderPass>(object), Deleter<VkRenderPass>(vk, device));
+}
+
+Move<VkCmdPool> createCommandPool (const DeviceInterface& vk, VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo)
+{
+	VkCmdPool object = 0;
+	VK_CHECK(vk.createCommandPool(device, pCreateInfo, &object));
+	return Move<VkCmdPool>(check<VkCmdPool>(object), Deleter<VkCmdPool>(vk, device));
+}
+
+Move<VkCmdBuffer> createCommandBuffer (const DeviceInterface& vk, VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo)
+{
+	VkCmdBuffer object = 0;
+	VK_CHECK(vk.createCommandBuffer(device, pCreateInfo, &object));
+	return Move<VkCmdBuffer>(check<VkCmdBuffer>(object), Deleter<VkCmdBuffer>(vk, device));
+}
+
diff --git a/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp b/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
new file mode 100644
index 0000000..4b592ce
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
@@ -0,0 +1,122 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V assembly to binary.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkSpirVAsm.hpp"
+#include "vkSpirVProgram.hpp"
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+#include "deClock.h"
+#include "qpDebugOut.h"
+
+#if defined(DEQP_HAVE_SPIRV_TOOLS)
+#	include "deSingleton.h"
+
+#	include "libspirv/libspirv.h"
+#endif
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+
+#if defined(DEQP_HAVE_SPIRV_TOOLS)
+
+namespace
+{
+static volatile deSingletonState	s_spirvInitState	= DE_SINGLETON_STATE_NOT_INITIALIZED;
+static			spv_opcode_table	s_spirvOpcodeTable;
+static			spv_operand_table	s_spirvOperandTable;
+static			spv_ext_inst_table	s_spirvExtInstTable;
+
+void initSpirVTools (void*)
+{
+	if (spvOpcodeTableGet(&s_spirvOpcodeTable) != SPV_SUCCESS)
+		TCU_THROW(InternalError, "Cannot get opcode table for assembly");
+
+	if (spvOperandTableGet(&s_spirvOperandTable) != SPV_SUCCESS)
+		TCU_THROW(InternalError, "Cannot get operand table for assembly");
+
+	if (spvExtInstTableGet(&s_spirvExtInstTable) != SPV_SUCCESS)
+		TCU_THROW(InternalError, "Cannot get external instruction table for assembly");
+}
+
+void prepareSpirvTools (void)
+{
+	deInitSingleton(&s_spirvInitState, initSpirVTools, DE_NULL);
+}
+
+} // anonymous
+
+void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo)
+{
+	prepareSpirvTools();
+
+	const std::string&	spvSource			= program->program.str();
+	spv_binary			binary				= DE_NULL;
+	spv_diagnostic		diagnostic			= DE_NULL;
+	const deUint64		compileStartTime	= deGetMicroseconds();
+	const spv_result_t	compileOk			= spvTextToBinary(spvSource.c_str(), spvSource.size(), s_spirvOpcodeTable, s_spirvOperandTable, s_spirvExtInstTable, &binary, &diagnostic);
+
+	{
+		buildInfo->source			= program;
+		buildInfo->infoLog			= diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
+		buildInfo->compileTimeUs	= deGetMicroseconds() - compileStartTime;
+		buildInfo->compileOk		= (compileOk == SPV_SUCCESS);
+	}
+
+	if (compileOk != SPV_SUCCESS)
+		TCU_FAIL("Failed to compile shader");
+
+	dst->resize((int)binary->wordCount * sizeof(deUint32));
+#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
+	deMemcpy(&(*dst)[0], &binary->code[0], dst->size());
+#else
+#	error "Big-endian not supported"
+#endif
+	spvBinaryDestroy(binary);
+	spvDiagnosticDestroy(diagnostic);
+	return;
+}
+
+#else // defined(DEQP_HAVE_SPIRV_TOOLS)
+
+void assembleSpirV (const SpirVAsmSource*, std::vector<deUint8>*, SpirVProgramInfo*)
+{
+	TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
+}
+
+#endif
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkSpirVAsm.hpp b/external/vulkancts/framework/vulkan/vkSpirVAsm.hpp
new file mode 100644
index 0000000..2897ecd
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkSpirVAsm.hpp
@@ -0,0 +1,48 @@
+#ifndef _VKSPIRVASM_HPP
+#define _VKSPIRVASM_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V assembly to binary.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkPrograms.hpp"
+
+namespace vk
+{
+
+//! Assemble SPIR-V program. Will fail with NotSupportedError if compiler is not available.
+void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo);
+
+} // vk
+
+#endif // _VKSPIRVASM_HPP
diff --git a/external/vulkancts/framework/vulkan/vkSpirVProgram.cpp b/external/vulkancts/framework/vulkan/vkSpirVProgram.cpp
new file mode 100644
index 0000000..cd73668
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkSpirVProgram.cpp
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Spirv program and binary info.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkSpirVProgram.hpp"
+
+#include "tcuTestLog.hpp"
+
+namespace vk
+{
+
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo)
+{
+	log << tcu::TestLog::ShaderProgram(shaderInfo.compileOk , shaderInfo.infoLog) << tcu::TestLog::EndShaderProgram;
+
+	// Write statistics
+	log << tcu::TestLog::Float(	"SpirVAssemblyTime",
+								"SpirV assembly time",
+								"ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
+	return log;
+}
+
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVAsmSource& source)
+{
+	log << tcu::TestLog::KernelSource(source.program.str());
+
+	return log;
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp b/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
new file mode 100644
index 0000000..f6717c4
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
@@ -0,0 +1,75 @@
+#ifndef _VKSPIRVPROGRAM_HPP
+#define _VKSPIRVPROGRAM_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V program and binary info.
+ *//*--------------------------------------------------------------------*/
+
+#include <sstream>
+
+#include "vkDefs.hpp"
+#include "tcuTestLog.hpp"
+
+namespace vk
+{
+
+struct SpirVAsmSource
+{
+	SpirVAsmSource& operator<<(const char* val)
+	{
+		program << val;
+		return *this;
+	}
+	std::ostringstream program;
+};
+
+struct SpirVProgramInfo
+{
+	SpirVProgramInfo()
+		: source		(DE_NULL)
+		, compileTimeUs	(0)
+		, compileOk		(false)
+	{
+	}
+
+	const SpirVAsmSource*	source;
+	std::string				infoLog;
+	deUint64				compileTimeUs;
+	bool					compileOk;
+};
+
+tcu::TestLog&	operator<<			(tcu::TestLog& log, const SpirVProgramInfo& shaderInfo);
+tcu::TestLog&	operator<<			(tcu::TestLog& log, const SpirVAsmSource& program);
+
+}
+
+#endif // _VKSPIRVPROGRAM_HPP
diff --git a/external/vulkancts/framework/vulkan/vkStrUtil.cpp b/external/vulkancts/framework/vulkan/vkStrUtil.cpp
new file mode 100644
index 0000000..6e63994
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkStrUtil.cpp
@@ -0,0 +1,62 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Pretty-printing and logging utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkStrUtil.hpp"
+
+namespace vk
+{
+
+struct CharPtr
+{
+	const char*	ptr;
+
+	CharPtr (const char* ptr_) : ptr(ptr_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const CharPtr& ptr)
+{
+	if (!ptr.ptr)
+		return str << "(null)";
+	else
+		return str << '"' << ptr.ptr << '"';
+}
+
+inline CharPtr getCharPtrStr (const char* ptr)
+{
+	return CharPtr(ptr);
+}
+
+#include "vkStrUtilImpl.inl"
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkStrUtil.hpp b/external/vulkancts/framework/vulkan/vkStrUtil.hpp
new file mode 100644
index 0000000..b4f676d
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkStrUtil.hpp
@@ -0,0 +1,56 @@
+#ifndef _VKSTRUTIL_HPP
+#define _VKSTRUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Pretty-printing and logging utilities.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "tcuFormatUtil.hpp"
+
+namespace vk
+{
+
+#include "vkStrUtil.inl"
+
+template<typename T>
+const char*	getTypeName	(void);
+
+template<HandleType Type>
+inline std::ostream& operator<< (std::ostream& s, const Handle<Type>& handle)
+{
+	return s << tcu::toHex(handle.getInternal());
+}
+
+} // vk
+
+#endif // _VKSTRUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkStrUtil.inl b/external/vulkancts/framework/vulkan/vkStrUtil.inl
new file mode 100644
index 0000000..1c17537
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkStrUtil.inl
@@ -0,0 +1,254 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+const char*	getResultName				(VkResult value);
+const char*	getStructureTypeName		(VkStructureType value);
+const char*	getSystemAllocTypeName		(VkSystemAllocType value);
+const char*	getFormatName				(VkFormat value);
+const char*	getImageTypeName			(VkImageType value);
+const char*	getImageTilingName			(VkImageTiling value);
+const char*	getPhysicalDeviceTypeName	(VkPhysicalDeviceType value);
+const char*	getImageAspectName			(VkImageAspect value);
+const char*	getQueryTypeName			(VkQueryType value);
+const char*	getSharingModeName			(VkSharingMode value);
+const char*	getImageLayoutName			(VkImageLayout value);
+const char*	getImageViewTypeName		(VkImageViewType value);
+const char*	getChannelSwizzleName		(VkChannelSwizzle value);
+const char*	getShaderStageName			(VkShaderStage value);
+const char*	getVertexInputStepRateName	(VkVertexInputStepRate value);
+const char*	getPrimitiveTopologyName	(VkPrimitiveTopology value);
+const char*	getFillModeName				(VkFillMode value);
+const char*	getCullModeName				(VkCullMode value);
+const char*	getFrontFaceName			(VkFrontFace value);
+const char*	getCompareOpName			(VkCompareOp value);
+const char*	getStencilOpName			(VkStencilOp value);
+const char*	getLogicOpName				(VkLogicOp value);
+const char*	getBlendName				(VkBlend value);
+const char*	getBlendOpName				(VkBlendOp value);
+const char*	getDynamicStateName			(VkDynamicState value);
+const char*	getTexFilterName			(VkTexFilter value);
+const char*	getTexMipmapModeName		(VkTexMipmapMode value);
+const char*	getTexAddressModeName		(VkTexAddressMode value);
+const char*	getBorderColorName			(VkBorderColor value);
+const char*	getDescriptorTypeName		(VkDescriptorType value);
+const char*	getDescriptorPoolUsageName	(VkDescriptorPoolUsage value);
+const char*	getDescriptorSetUsageName	(VkDescriptorSetUsage value);
+const char*	getAttachmentLoadOpName		(VkAttachmentLoadOp value);
+const char*	getAttachmentStoreOpName	(VkAttachmentStoreOp value);
+const char*	getPipelineBindPointName	(VkPipelineBindPoint value);
+const char*	getCmdBufferLevelName		(VkCmdBufferLevel value);
+const char*	getIndexTypeName			(VkIndexType value);
+const char*	getTimestampTypeName		(VkTimestampType value);
+const char*	getRenderPassContentsName	(VkRenderPassContents value);
+
+inline tcu::Format::Enum<VkResult>				getResultStr				(VkResult value)				{ return tcu::Format::Enum<VkResult>(getResultName, value);								}
+inline tcu::Format::Enum<VkStructureType>		getStructureTypeStr			(VkStructureType value)			{ return tcu::Format::Enum<VkStructureType>(getStructureTypeName, value);				}
+inline tcu::Format::Enum<VkSystemAllocType>		getSystemAllocTypeStr		(VkSystemAllocType value)		{ return tcu::Format::Enum<VkSystemAllocType>(getSystemAllocTypeName, value);			}
+inline tcu::Format::Enum<VkFormat>				getFormatStr				(VkFormat value)				{ return tcu::Format::Enum<VkFormat>(getFormatName, value);								}
+inline tcu::Format::Enum<VkImageType>			getImageTypeStr				(VkImageType value)				{ return tcu::Format::Enum<VkImageType>(getImageTypeName, value);						}
+inline tcu::Format::Enum<VkImageTiling>			getImageTilingStr			(VkImageTiling value)			{ return tcu::Format::Enum<VkImageTiling>(getImageTilingName, value);					}
+inline tcu::Format::Enum<VkPhysicalDeviceType>	getPhysicalDeviceTypeStr	(VkPhysicalDeviceType value)	{ return tcu::Format::Enum<VkPhysicalDeviceType>(getPhysicalDeviceTypeName, value);		}
+inline tcu::Format::Enum<VkImageAspect>			getImageAspectStr			(VkImageAspect value)			{ return tcu::Format::Enum<VkImageAspect>(getImageAspectName, value);					}
+inline tcu::Format::Enum<VkQueryType>			getQueryTypeStr				(VkQueryType value)				{ return tcu::Format::Enum<VkQueryType>(getQueryTypeName, value);						}
+inline tcu::Format::Enum<VkSharingMode>			getSharingModeStr			(VkSharingMode value)			{ return tcu::Format::Enum<VkSharingMode>(getSharingModeName, value);					}
+inline tcu::Format::Enum<VkImageLayout>			getImageLayoutStr			(VkImageLayout value)			{ return tcu::Format::Enum<VkImageLayout>(getImageLayoutName, value);					}
+inline tcu::Format::Enum<VkImageViewType>		getImageViewTypeStr			(VkImageViewType value)			{ return tcu::Format::Enum<VkImageViewType>(getImageViewTypeName, value);				}
+inline tcu::Format::Enum<VkChannelSwizzle>		getChannelSwizzleStr		(VkChannelSwizzle value)		{ return tcu::Format::Enum<VkChannelSwizzle>(getChannelSwizzleName, value);				}
+inline tcu::Format::Enum<VkShaderStage>			getShaderStageStr			(VkShaderStage value)			{ return tcu::Format::Enum<VkShaderStage>(getShaderStageName, value);					}
+inline tcu::Format::Enum<VkVertexInputStepRate>	getVertexInputStepRateStr	(VkVertexInputStepRate value)	{ return tcu::Format::Enum<VkVertexInputStepRate>(getVertexInputStepRateName, value);	}
+inline tcu::Format::Enum<VkPrimitiveTopology>	getPrimitiveTopologyStr		(VkPrimitiveTopology value)		{ return tcu::Format::Enum<VkPrimitiveTopology>(getPrimitiveTopologyName, value);		}
+inline tcu::Format::Enum<VkFillMode>			getFillModeStr				(VkFillMode value)				{ return tcu::Format::Enum<VkFillMode>(getFillModeName, value);							}
+inline tcu::Format::Enum<VkCullMode>			getCullModeStr				(VkCullMode value)				{ return tcu::Format::Enum<VkCullMode>(getCullModeName, value);							}
+inline tcu::Format::Enum<VkFrontFace>			getFrontFaceStr				(VkFrontFace value)				{ return tcu::Format::Enum<VkFrontFace>(getFrontFaceName, value);						}
+inline tcu::Format::Enum<VkCompareOp>			getCompareOpStr				(VkCompareOp value)				{ return tcu::Format::Enum<VkCompareOp>(getCompareOpName, value);						}
+inline tcu::Format::Enum<VkStencilOp>			getStencilOpStr				(VkStencilOp value)				{ return tcu::Format::Enum<VkStencilOp>(getStencilOpName, value);						}
+inline tcu::Format::Enum<VkLogicOp>				getLogicOpStr				(VkLogicOp value)				{ return tcu::Format::Enum<VkLogicOp>(getLogicOpName, value);							}
+inline tcu::Format::Enum<VkBlend>				getBlendStr					(VkBlend value)					{ return tcu::Format::Enum<VkBlend>(getBlendName, value);								}
+inline tcu::Format::Enum<VkBlendOp>				getBlendOpStr				(VkBlendOp value)				{ return tcu::Format::Enum<VkBlendOp>(getBlendOpName, value);							}
+inline tcu::Format::Enum<VkDynamicState>		getDynamicStateStr			(VkDynamicState value)			{ return tcu::Format::Enum<VkDynamicState>(getDynamicStateName, value);					}
+inline tcu::Format::Enum<VkTexFilter>			getTexFilterStr				(VkTexFilter value)				{ return tcu::Format::Enum<VkTexFilter>(getTexFilterName, value);						}
+inline tcu::Format::Enum<VkTexMipmapMode>		getTexMipmapModeStr			(VkTexMipmapMode value)			{ return tcu::Format::Enum<VkTexMipmapMode>(getTexMipmapModeName, value);				}
+inline tcu::Format::Enum<VkTexAddressMode>		getTexAddressModeStr		(VkTexAddressMode value)		{ return tcu::Format::Enum<VkTexAddressMode>(getTexAddressModeName, value);				}
+inline tcu::Format::Enum<VkBorderColor>			getBorderColorStr			(VkBorderColor value)			{ return tcu::Format::Enum<VkBorderColor>(getBorderColorName, value);					}
+inline tcu::Format::Enum<VkDescriptorType>		getDescriptorTypeStr		(VkDescriptorType value)		{ return tcu::Format::Enum<VkDescriptorType>(getDescriptorTypeName, value);				}
+inline tcu::Format::Enum<VkDescriptorPoolUsage>	getDescriptorPoolUsageStr	(VkDescriptorPoolUsage value)	{ return tcu::Format::Enum<VkDescriptorPoolUsage>(getDescriptorPoolUsageName, value);	}
+inline tcu::Format::Enum<VkDescriptorSetUsage>	getDescriptorSetUsageStr	(VkDescriptorSetUsage value)	{ return tcu::Format::Enum<VkDescriptorSetUsage>(getDescriptorSetUsageName, value);		}
+inline tcu::Format::Enum<VkAttachmentLoadOp>	getAttachmentLoadOpStr		(VkAttachmentLoadOp value)		{ return tcu::Format::Enum<VkAttachmentLoadOp>(getAttachmentLoadOpName, value);			}
+inline tcu::Format::Enum<VkAttachmentStoreOp>	getAttachmentStoreOpStr		(VkAttachmentStoreOp value)		{ return tcu::Format::Enum<VkAttachmentStoreOp>(getAttachmentStoreOpName, value);		}
+inline tcu::Format::Enum<VkPipelineBindPoint>	getPipelineBindPointStr		(VkPipelineBindPoint value)		{ return tcu::Format::Enum<VkPipelineBindPoint>(getPipelineBindPointName, value);		}
+inline tcu::Format::Enum<VkCmdBufferLevel>		getCmdBufferLevelStr		(VkCmdBufferLevel value)		{ return tcu::Format::Enum<VkCmdBufferLevel>(getCmdBufferLevelName, value);				}
+inline tcu::Format::Enum<VkIndexType>			getIndexTypeStr				(VkIndexType value)				{ return tcu::Format::Enum<VkIndexType>(getIndexTypeName, value);						}
+inline tcu::Format::Enum<VkTimestampType>		getTimestampTypeStr			(VkTimestampType value)			{ return tcu::Format::Enum<VkTimestampType>(getTimestampTypeName, value);				}
+inline tcu::Format::Enum<VkRenderPassContents>	getRenderPassContentsStr	(VkRenderPassContents value)	{ return tcu::Format::Enum<VkRenderPassContents>(getRenderPassContentsName, value);		}
+
+inline std::ostream&	operator<<	(std::ostream& s, VkResult value)				{ return s << getResultStr(value);				}
+inline std::ostream&	operator<<	(std::ostream& s, VkStructureType value)		{ return s << getStructureTypeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkSystemAllocType value)		{ return s << getSystemAllocTypeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkFormat value)				{ return s << getFormatStr(value);				}
+inline std::ostream&	operator<<	(std::ostream& s, VkImageType value)			{ return s << getImageTypeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkImageTiling value)			{ return s << getImageTilingStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkPhysicalDeviceType value)	{ return s << getPhysicalDeviceTypeStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkImageAspect value)			{ return s << getImageAspectStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkQueryType value)			{ return s << getQueryTypeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkSharingMode value)			{ return s << getSharingModeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkImageLayout value)			{ return s << getImageLayoutStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkImageViewType value)		{ return s << getImageViewTypeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkChannelSwizzle value)		{ return s << getChannelSwizzleStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkShaderStage value)			{ return s << getShaderStageStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkVertexInputStepRate value)	{ return s << getVertexInputStepRateStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkPrimitiveTopology value)	{ return s << getPrimitiveTopologyStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkFillMode value)				{ return s << getFillModeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkCullMode value)				{ return s << getCullModeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkFrontFace value)			{ return s << getFrontFaceStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkCompareOp value)			{ return s << getCompareOpStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkStencilOp value)			{ return s << getStencilOpStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkLogicOp value)				{ return s << getLogicOpStr(value);				}
+inline std::ostream&	operator<<	(std::ostream& s, VkBlend value)				{ return s << getBlendStr(value);				}
+inline std::ostream&	operator<<	(std::ostream& s, VkBlendOp value)				{ return s << getBlendOpStr(value);				}
+inline std::ostream&	operator<<	(std::ostream& s, VkDynamicState value)			{ return s << getDynamicStateStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkTexFilter value)			{ return s << getTexFilterStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkTexMipmapMode value)		{ return s << getTexMipmapModeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkTexAddressMode value)		{ return s << getTexAddressModeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkBorderColor value)			{ return s << getBorderColorStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkDescriptorType value)		{ return s << getDescriptorTypeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkDescriptorPoolUsage value)	{ return s << getDescriptorPoolUsageStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkDescriptorSetUsage value)	{ return s << getDescriptorSetUsageStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkAttachmentLoadOp value)		{ return s << getAttachmentLoadOpStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkAttachmentStoreOp value)	{ return s << getAttachmentStoreOpStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkPipelineBindPoint value)	{ return s << getPipelineBindPointStr(value);	}
+inline std::ostream&	operator<<	(std::ostream& s, VkCmdBufferLevel value)		{ return s << getCmdBufferLevelStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkIndexType value)			{ return s << getIndexTypeStr(value);			}
+inline std::ostream&	operator<<	(std::ostream& s, VkTimestampType value)		{ return s << getTimestampTypeStr(value);		}
+inline std::ostream&	operator<<	(std::ostream& s, VkRenderPassContents value)	{ return s << getRenderPassContentsStr(value);	}
+
+tcu::Format::Bitfield<32>	getFormatFeatureFlagsStr			(VkFormatFeatureFlags value);
+tcu::Format::Bitfield<32>	getImageUsageFlagsStr				(VkImageUsageFlags value);
+tcu::Format::Bitfield<32>	getImageCreateFlagsStr				(VkImageCreateFlags value);
+tcu::Format::Bitfield<32>	getSampleCountFlagsStr				(VkSampleCountFlags value);
+tcu::Format::Bitfield<32>	getQueueFlagsStr					(VkQueueFlags value);
+tcu::Format::Bitfield<32>	getMemoryPropertyFlagsStr			(VkMemoryPropertyFlags value);
+tcu::Format::Bitfield<32>	getMemoryHeapFlagsStr				(VkMemoryHeapFlags value);
+tcu::Format::Bitfield<32>	getSparseImageFormatFlagsStr		(VkSparseImageFormatFlags value);
+tcu::Format::Bitfield<32>	getSparseMemoryBindFlagsStr			(VkSparseMemoryBindFlags value);
+tcu::Format::Bitfield<32>	getFenceCreateFlagsStr				(VkFenceCreateFlags value);
+tcu::Format::Bitfield<32>	getQueryPipelineStatisticFlagsStr	(VkQueryPipelineStatisticFlags value);
+tcu::Format::Bitfield<32>	getQueryResultFlagsStr				(VkQueryResultFlags value);
+tcu::Format::Bitfield<32>	getBufferUsageFlagsStr				(VkBufferUsageFlags value);
+tcu::Format::Bitfield<32>	getBufferCreateFlagsStr				(VkBufferCreateFlags value);
+tcu::Format::Bitfield<32>	getImageAspectFlagsStr				(VkImageAspectFlags value);
+tcu::Format::Bitfield<32>	getImageViewCreateFlagsStr			(VkImageViewCreateFlags value);
+tcu::Format::Bitfield<32>	getChannelFlagsStr					(VkChannelFlags value);
+tcu::Format::Bitfield<32>	getPipelineCreateFlagsStr			(VkPipelineCreateFlags value);
+tcu::Format::Bitfield<32>	getShaderStageFlagsStr				(VkShaderStageFlags value);
+tcu::Format::Bitfield<32>	getAttachmentDescriptionFlagsStr	(VkAttachmentDescriptionFlags value);
+tcu::Format::Bitfield<32>	getSubpassDescriptionFlagsStr		(VkSubpassDescriptionFlags value);
+tcu::Format::Bitfield<32>	getPipelineStageFlagsStr			(VkPipelineStageFlags value);
+tcu::Format::Bitfield<32>	getMemoryOutputFlagsStr				(VkMemoryOutputFlags value);
+tcu::Format::Bitfield<32>	getMemoryInputFlagsStr				(VkMemoryInputFlags value);
+tcu::Format::Bitfield<32>	getCmdPoolCreateFlagsStr			(VkCmdPoolCreateFlags value);
+tcu::Format::Bitfield<32>	getCmdPoolResetFlagsStr				(VkCmdPoolResetFlags value);
+tcu::Format::Bitfield<32>	getCmdBufferOptimizeFlagsStr		(VkCmdBufferOptimizeFlags value);
+tcu::Format::Bitfield<32>	getCmdBufferResetFlagsStr			(VkCmdBufferResetFlags value);
+tcu::Format::Bitfield<32>	getStencilFaceFlagsStr				(VkStencilFaceFlags value);
+tcu::Format::Bitfield<32>	getQueryControlFlagsStr				(VkQueryControlFlags value);
+
+std::ostream&	operator<<	(std::ostream& s, const VkApplicationInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkAllocCallbacks& value);
+std::ostream&	operator<<	(std::ostream& s, const VkInstanceCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPhysicalDeviceFeatures& value);
+std::ostream&	operator<<	(std::ostream& s, const VkFormatProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkExtent3D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageFormatProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPhysicalDeviceLimits& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPhysicalDeviceSparseProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPhysicalDeviceProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkQueueFamilyProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMemoryType& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMemoryHeap& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPhysicalDeviceMemoryProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDeviceQueueCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDeviceCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkExtensionProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkLayerProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMemoryAllocInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMappedMemoryRange& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMemoryRequirements& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSparseImageFormatProperties& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSparseImageMemoryRequirements& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSparseMemoryBindInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageSubresource& value);
+std::ostream&	operator<<	(std::ostream& s, const VkOffset3D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSparseImageMemoryBindInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkFenceCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSemaphoreCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkEventCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkQueryPoolCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkBufferCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkBufferViewCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSubresourceLayout& value);
+std::ostream&	operator<<	(std::ostream& s, const VkChannelMapping& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageSubresourceRange& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageViewCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkShaderModuleCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkShaderCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineCacheCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSpecializationMapEntry& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSpecializationInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineShaderStageCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkVertexInputBindingDescription& value);
+std::ostream&	operator<<	(std::ostream& s, const VkVertexInputAttributeDescription& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineVertexInputStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineInputAssemblyStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineTessellationStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkViewport& value);
+std::ostream&	operator<<	(std::ostream& s, const VkOffset2D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkExtent2D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkRect2D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineViewportStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineRasterStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineMultisampleStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkStencilOpState& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineDepthStencilStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineColorBlendAttachmentState& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineColorBlendStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineDynamicStateCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkGraphicsPipelineCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkComputePipelineCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPushConstantRange& value);
+std::ostream&	operator<<	(std::ostream& s, const VkPipelineLayoutCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSamplerCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorSetLayoutBinding& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorSetLayoutCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorTypeCount& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorPoolCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorBufferInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDescriptorInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkWriteDescriptorSet& value);
+std::ostream&	operator<<	(std::ostream& s, const VkCopyDescriptorSet& value);
+std::ostream&	operator<<	(std::ostream& s, const VkFramebufferCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkAttachmentDescription& value);
+std::ostream&	operator<<	(std::ostream& s, const VkAttachmentReference& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSubpassDescription& value);
+std::ostream&	operator<<	(std::ostream& s, const VkSubpassDependency& value);
+std::ostream&	operator<<	(std::ostream& s, const VkRenderPassCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkCmdPoolCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkCmdBufferCreateInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkCmdBufferBeginInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkBufferCopy& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageSubresourceCopy& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageCopy& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageBlit& value);
+std::ostream&	operator<<	(std::ostream& s, const VkBufferImageCopy& value);
+std::ostream&	operator<<	(std::ostream& s, const VkClearColorValue& value);
+std::ostream&	operator<<	(std::ostream& s, const VkClearDepthStencilValue& value);
+std::ostream&	operator<<	(std::ostream& s, const VkRect3D& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageResolve& value);
+std::ostream&	operator<<	(std::ostream& s, const VkClearValue& value);
+std::ostream&	operator<<	(std::ostream& s, const VkRenderPassBeginInfo& value);
+std::ostream&	operator<<	(std::ostream& s, const VkBufferMemoryBarrier& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDispatchIndirectCmd& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDrawIndexedIndirectCmd& value);
+std::ostream&	operator<<	(std::ostream& s, const VkDrawIndirectCmd& value);
+std::ostream&	operator<<	(std::ostream& s, const VkImageMemoryBarrier& value);
+std::ostream&	operator<<	(std::ostream& s, const VkMemoryBarrier& value);
diff --git a/external/vulkancts/framework/vulkan/vkStrUtilImpl.inl b/external/vulkancts/framework/vulkan/vkStrUtilImpl.inl
new file mode 100644
index 0000000..25186bc
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkStrUtilImpl.inl
@@ -0,0 +1,2526 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+template<> const char*	getTypeName<VkInstance>				(void) { return "VkInstance";				}
+template<> const char*	getTypeName<VkPhysicalDevice>		(void) { return "VkPhysicalDevice";			}
+template<> const char*	getTypeName<VkDevice>				(void) { return "VkDevice";					}
+template<> const char*	getTypeName<VkQueue>				(void) { return "VkQueue";					}
+template<> const char*	getTypeName<VkCmdBuffer>			(void) { return "VkCmdBuffer";				}
+template<> const char*	getTypeName<VkFence>				(void) { return "VkFence";					}
+template<> const char*	getTypeName<VkDeviceMemory>			(void) { return "VkDeviceMemory";			}
+template<> const char*	getTypeName<VkBuffer>				(void) { return "VkBuffer";					}
+template<> const char*	getTypeName<VkImage>				(void) { return "VkImage";					}
+template<> const char*	getTypeName<VkSemaphore>			(void) { return "VkSemaphore";				}
+template<> const char*	getTypeName<VkEvent>				(void) { return "VkEvent";					}
+template<> const char*	getTypeName<VkQueryPool>			(void) { return "VkQueryPool";				}
+template<> const char*	getTypeName<VkBufferView>			(void) { return "VkBufferView";				}
+template<> const char*	getTypeName<VkImageView>			(void) { return "VkImageView";				}
+template<> const char*	getTypeName<VkShaderModule>			(void) { return "VkShaderModule";			}
+template<> const char*	getTypeName<VkShader>				(void) { return "VkShader";					}
+template<> const char*	getTypeName<VkPipelineCache>		(void) { return "VkPipelineCache";			}
+template<> const char*	getTypeName<VkPipelineLayout>		(void) { return "VkPipelineLayout";			}
+template<> const char*	getTypeName<VkRenderPass>			(void) { return "VkRenderPass";				}
+template<> const char*	getTypeName<VkPipeline>				(void) { return "VkPipeline";				}
+template<> const char*	getTypeName<VkDescriptorSetLayout>	(void) { return "VkDescriptorSetLayout";	}
+template<> const char*	getTypeName<VkSampler>				(void) { return "VkSampler";				}
+template<> const char*	getTypeName<VkDescriptorPool>		(void) { return "VkDescriptorPool";			}
+template<> const char*	getTypeName<VkDescriptorSet>		(void) { return "VkDescriptorSet";			}
+template<> const char*	getTypeName<VkFramebuffer>			(void) { return "VkFramebuffer";			}
+template<> const char*	getTypeName<VkCmdPool>				(void) { return "VkCmdPool";				}
+
+const char* getResultName (VkResult value)
+{
+	switch (value)
+	{
+		case VK_SUCCESS:						return "VK_SUCCESS";
+		case VK_UNSUPPORTED:					return "VK_UNSUPPORTED";
+		case VK_NOT_READY:						return "VK_NOT_READY";
+		case VK_TIMEOUT:						return "VK_TIMEOUT";
+		case VK_EVENT_SET:						return "VK_EVENT_SET";
+		case VK_EVENT_RESET:					return "VK_EVENT_RESET";
+		case VK_INCOMPLETE:						return "VK_INCOMPLETE";
+		case VK_ERROR_OUT_OF_HOST_MEMORY:		return "VK_ERROR_OUT_OF_HOST_MEMORY";
+		case VK_ERROR_OUT_OF_DEVICE_MEMORY:		return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
+		case VK_ERROR_INITIALIZATION_FAILED:	return "VK_ERROR_INITIALIZATION_FAILED";
+		case VK_ERROR_DEVICE_LOST:				return "VK_ERROR_DEVICE_LOST";
+		case VK_ERROR_MEMORY_MAP_FAILED:		return "VK_ERROR_MEMORY_MAP_FAILED";
+		case VK_ERROR_LAYER_NOT_PRESENT:		return "VK_ERROR_LAYER_NOT_PRESENT";
+		case VK_ERROR_EXTENSION_NOT_PRESENT:	return "VK_ERROR_EXTENSION_NOT_PRESENT";
+		case VK_ERROR_INCOMPATIBLE_DRIVER:		return "VK_ERROR_INCOMPATIBLE_DRIVER";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getStructureTypeName (VkStructureType value)
+{
+	switch (value)
+	{
+		case VK_STRUCTURE_TYPE_APPLICATION_INFO:							return "VK_STRUCTURE_TYPE_APPLICATION_INFO";
+		case VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO:							return "VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO:							return "VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO";
+		case VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO:						return "VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO:					return "VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_SHADER_CREATE_INFO:							return "VK_STRUCTURE_TYPE_SHADER_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO:				return "VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO:							return "VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO:			return "VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO:						return "VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_EVENT_CREATE_INFO:							return "VK_STRUCTURE_TYPE_EVENT_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_FENCE_CREATE_INFO:							return "VK_STRUCTURE_TYPE_FENCE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO:						return "VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO:						return "VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO:			return "VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:				return "VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO:		return "VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO:	return "VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO:		return "VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO:			return "VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO:			return "VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO:		return "VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO:		return "VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO:	return "VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO:							return "VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO:							return "VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO:						return "VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO:						return "VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO:						return "VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO";
+		case VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO:						return "VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_MEMORY_BARRIER:								return "VK_STRUCTURE_TYPE_MEMORY_BARRIER";
+		case VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER:						return "VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER";
+		case VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER:						return "VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER";
+		case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO:					return "VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:						return "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET";
+		case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:							return "VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET";
+		case VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO:						return "VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO:					return "VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE:							return "VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE";
+		case VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO:					return "VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION:						return "VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION";
+		case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION:							return "VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION";
+		case VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY:							return "VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY";
+		case VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO:						return "VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO";
+		case VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO:						return "VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO:					return "VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO";
+		case VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO:			return "VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO";
+		default:															return DE_NULL;
+	}
+}
+
+const char* getSystemAllocTypeName (VkSystemAllocType value)
+{
+	switch (value)
+	{
+		case VK_SYSTEM_ALLOC_TYPE_API_OBJECT:		return "VK_SYSTEM_ALLOC_TYPE_API_OBJECT";
+		case VK_SYSTEM_ALLOC_TYPE_INTERNAL:			return "VK_SYSTEM_ALLOC_TYPE_INTERNAL";
+		case VK_SYSTEM_ALLOC_TYPE_INTERNAL_TEMP:	return "VK_SYSTEM_ALLOC_TYPE_INTERNAL_TEMP";
+		case VK_SYSTEM_ALLOC_TYPE_INTERNAL_SHADER:	return "VK_SYSTEM_ALLOC_TYPE_INTERNAL_SHADER";
+		case VK_SYSTEM_ALLOC_TYPE_DEBUG:			return "VK_SYSTEM_ALLOC_TYPE_DEBUG";
+		default:									return DE_NULL;
+	}
+}
+
+const char* getFormatName (VkFormat value)
+{
+	switch (value)
+	{
+		case VK_FORMAT_UNDEFINED:				return "VK_FORMAT_UNDEFINED";
+		case VK_FORMAT_R4G4_UNORM:				return "VK_FORMAT_R4G4_UNORM";
+		case VK_FORMAT_R4G4_USCALED:			return "VK_FORMAT_R4G4_USCALED";
+		case VK_FORMAT_R4G4B4A4_UNORM:			return "VK_FORMAT_R4G4B4A4_UNORM";
+		case VK_FORMAT_R4G4B4A4_USCALED:		return "VK_FORMAT_R4G4B4A4_USCALED";
+		case VK_FORMAT_R5G6B5_UNORM:			return "VK_FORMAT_R5G6B5_UNORM";
+		case VK_FORMAT_R5G6B5_USCALED:			return "VK_FORMAT_R5G6B5_USCALED";
+		case VK_FORMAT_R5G5B5A1_UNORM:			return "VK_FORMAT_R5G5B5A1_UNORM";
+		case VK_FORMAT_R5G5B5A1_USCALED:		return "VK_FORMAT_R5G5B5A1_USCALED";
+		case VK_FORMAT_R8_UNORM:				return "VK_FORMAT_R8_UNORM";
+		case VK_FORMAT_R8_SNORM:				return "VK_FORMAT_R8_SNORM";
+		case VK_FORMAT_R8_USCALED:				return "VK_FORMAT_R8_USCALED";
+		case VK_FORMAT_R8_SSCALED:				return "VK_FORMAT_R8_SSCALED";
+		case VK_FORMAT_R8_UINT:					return "VK_FORMAT_R8_UINT";
+		case VK_FORMAT_R8_SINT:					return "VK_FORMAT_R8_SINT";
+		case VK_FORMAT_R8_SRGB:					return "VK_FORMAT_R8_SRGB";
+		case VK_FORMAT_R8G8_UNORM:				return "VK_FORMAT_R8G8_UNORM";
+		case VK_FORMAT_R8G8_SNORM:				return "VK_FORMAT_R8G8_SNORM";
+		case VK_FORMAT_R8G8_USCALED:			return "VK_FORMAT_R8G8_USCALED";
+		case VK_FORMAT_R8G8_SSCALED:			return "VK_FORMAT_R8G8_SSCALED";
+		case VK_FORMAT_R8G8_UINT:				return "VK_FORMAT_R8G8_UINT";
+		case VK_FORMAT_R8G8_SINT:				return "VK_FORMAT_R8G8_SINT";
+		case VK_FORMAT_R8G8_SRGB:				return "VK_FORMAT_R8G8_SRGB";
+		case VK_FORMAT_R8G8B8_UNORM:			return "VK_FORMAT_R8G8B8_UNORM";
+		case VK_FORMAT_R8G8B8_SNORM:			return "VK_FORMAT_R8G8B8_SNORM";
+		case VK_FORMAT_R8G8B8_USCALED:			return "VK_FORMAT_R8G8B8_USCALED";
+		case VK_FORMAT_R8G8B8_SSCALED:			return "VK_FORMAT_R8G8B8_SSCALED";
+		case VK_FORMAT_R8G8B8_UINT:				return "VK_FORMAT_R8G8B8_UINT";
+		case VK_FORMAT_R8G8B8_SINT:				return "VK_FORMAT_R8G8B8_SINT";
+		case VK_FORMAT_R8G8B8_SRGB:				return "VK_FORMAT_R8G8B8_SRGB";
+		case VK_FORMAT_R8G8B8A8_UNORM:			return "VK_FORMAT_R8G8B8A8_UNORM";
+		case VK_FORMAT_R8G8B8A8_SNORM:			return "VK_FORMAT_R8G8B8A8_SNORM";
+		case VK_FORMAT_R8G8B8A8_USCALED:		return "VK_FORMAT_R8G8B8A8_USCALED";
+		case VK_FORMAT_R8G8B8A8_SSCALED:		return "VK_FORMAT_R8G8B8A8_SSCALED";
+		case VK_FORMAT_R8G8B8A8_UINT:			return "VK_FORMAT_R8G8B8A8_UINT";
+		case VK_FORMAT_R8G8B8A8_SINT:			return "VK_FORMAT_R8G8B8A8_SINT";
+		case VK_FORMAT_R8G8B8A8_SRGB:			return "VK_FORMAT_R8G8B8A8_SRGB";
+		case VK_FORMAT_R10G10B10A2_UNORM:		return "VK_FORMAT_R10G10B10A2_UNORM";
+		case VK_FORMAT_R10G10B10A2_SNORM:		return "VK_FORMAT_R10G10B10A2_SNORM";
+		case VK_FORMAT_R10G10B10A2_USCALED:		return "VK_FORMAT_R10G10B10A2_USCALED";
+		case VK_FORMAT_R10G10B10A2_SSCALED:		return "VK_FORMAT_R10G10B10A2_SSCALED";
+		case VK_FORMAT_R10G10B10A2_UINT:		return "VK_FORMAT_R10G10B10A2_UINT";
+		case VK_FORMAT_R10G10B10A2_SINT:		return "VK_FORMAT_R10G10B10A2_SINT";
+		case VK_FORMAT_R16_UNORM:				return "VK_FORMAT_R16_UNORM";
+		case VK_FORMAT_R16_SNORM:				return "VK_FORMAT_R16_SNORM";
+		case VK_FORMAT_R16_USCALED:				return "VK_FORMAT_R16_USCALED";
+		case VK_FORMAT_R16_SSCALED:				return "VK_FORMAT_R16_SSCALED";
+		case VK_FORMAT_R16_UINT:				return "VK_FORMAT_R16_UINT";
+		case VK_FORMAT_R16_SINT:				return "VK_FORMAT_R16_SINT";
+		case VK_FORMAT_R16_SFLOAT:				return "VK_FORMAT_R16_SFLOAT";
+		case VK_FORMAT_R16G16_UNORM:			return "VK_FORMAT_R16G16_UNORM";
+		case VK_FORMAT_R16G16_SNORM:			return "VK_FORMAT_R16G16_SNORM";
+		case VK_FORMAT_R16G16_USCALED:			return "VK_FORMAT_R16G16_USCALED";
+		case VK_FORMAT_R16G16_SSCALED:			return "VK_FORMAT_R16G16_SSCALED";
+		case VK_FORMAT_R16G16_UINT:				return "VK_FORMAT_R16G16_UINT";
+		case VK_FORMAT_R16G16_SINT:				return "VK_FORMAT_R16G16_SINT";
+		case VK_FORMAT_R16G16_SFLOAT:			return "VK_FORMAT_R16G16_SFLOAT";
+		case VK_FORMAT_R16G16B16_UNORM:			return "VK_FORMAT_R16G16B16_UNORM";
+		case VK_FORMAT_R16G16B16_SNORM:			return "VK_FORMAT_R16G16B16_SNORM";
+		case VK_FORMAT_R16G16B16_USCALED:		return "VK_FORMAT_R16G16B16_USCALED";
+		case VK_FORMAT_R16G16B16_SSCALED:		return "VK_FORMAT_R16G16B16_SSCALED";
+		case VK_FORMAT_R16G16B16_UINT:			return "VK_FORMAT_R16G16B16_UINT";
+		case VK_FORMAT_R16G16B16_SINT:			return "VK_FORMAT_R16G16B16_SINT";
+		case VK_FORMAT_R16G16B16_SFLOAT:		return "VK_FORMAT_R16G16B16_SFLOAT";
+		case VK_FORMAT_R16G16B16A16_UNORM:		return "VK_FORMAT_R16G16B16A16_UNORM";
+		case VK_FORMAT_R16G16B16A16_SNORM:		return "VK_FORMAT_R16G16B16A16_SNORM";
+		case VK_FORMAT_R16G16B16A16_USCALED:	return "VK_FORMAT_R16G16B16A16_USCALED";
+		case VK_FORMAT_R16G16B16A16_SSCALED:	return "VK_FORMAT_R16G16B16A16_SSCALED";
+		case VK_FORMAT_R16G16B16A16_UINT:		return "VK_FORMAT_R16G16B16A16_UINT";
+		case VK_FORMAT_R16G16B16A16_SINT:		return "VK_FORMAT_R16G16B16A16_SINT";
+		case VK_FORMAT_R16G16B16A16_SFLOAT:		return "VK_FORMAT_R16G16B16A16_SFLOAT";
+		case VK_FORMAT_R32_UINT:				return "VK_FORMAT_R32_UINT";
+		case VK_FORMAT_R32_SINT:				return "VK_FORMAT_R32_SINT";
+		case VK_FORMAT_R32_SFLOAT:				return "VK_FORMAT_R32_SFLOAT";
+		case VK_FORMAT_R32G32_UINT:				return "VK_FORMAT_R32G32_UINT";
+		case VK_FORMAT_R32G32_SINT:				return "VK_FORMAT_R32G32_SINT";
+		case VK_FORMAT_R32G32_SFLOAT:			return "VK_FORMAT_R32G32_SFLOAT";
+		case VK_FORMAT_R32G32B32_UINT:			return "VK_FORMAT_R32G32B32_UINT";
+		case VK_FORMAT_R32G32B32_SINT:			return "VK_FORMAT_R32G32B32_SINT";
+		case VK_FORMAT_R32G32B32_SFLOAT:		return "VK_FORMAT_R32G32B32_SFLOAT";
+		case VK_FORMAT_R32G32B32A32_UINT:		return "VK_FORMAT_R32G32B32A32_UINT";
+		case VK_FORMAT_R32G32B32A32_SINT:		return "VK_FORMAT_R32G32B32A32_SINT";
+		case VK_FORMAT_R32G32B32A32_SFLOAT:		return "VK_FORMAT_R32G32B32A32_SFLOAT";
+		case VK_FORMAT_R64_SFLOAT:				return "VK_FORMAT_R64_SFLOAT";
+		case VK_FORMAT_R64G64_SFLOAT:			return "VK_FORMAT_R64G64_SFLOAT";
+		case VK_FORMAT_R64G64B64_SFLOAT:		return "VK_FORMAT_R64G64B64_SFLOAT";
+		case VK_FORMAT_R64G64B64A64_SFLOAT:		return "VK_FORMAT_R64G64B64A64_SFLOAT";
+		case VK_FORMAT_R11G11B10_UFLOAT:		return "VK_FORMAT_R11G11B10_UFLOAT";
+		case VK_FORMAT_R9G9B9E5_UFLOAT:			return "VK_FORMAT_R9G9B9E5_UFLOAT";
+		case VK_FORMAT_D16_UNORM:				return "VK_FORMAT_D16_UNORM";
+		case VK_FORMAT_D24_UNORM_X8:			return "VK_FORMAT_D24_UNORM_X8";
+		case VK_FORMAT_D32_SFLOAT:				return "VK_FORMAT_D32_SFLOAT";
+		case VK_FORMAT_S8_UINT:					return "VK_FORMAT_S8_UINT";
+		case VK_FORMAT_D16_UNORM_S8_UINT:		return "VK_FORMAT_D16_UNORM_S8_UINT";
+		case VK_FORMAT_D24_UNORM_S8_UINT:		return "VK_FORMAT_D24_UNORM_S8_UINT";
+		case VK_FORMAT_D32_SFLOAT_S8_UINT:		return "VK_FORMAT_D32_SFLOAT_S8_UINT";
+		case VK_FORMAT_BC1_RGB_UNORM:			return "VK_FORMAT_BC1_RGB_UNORM";
+		case VK_FORMAT_BC1_RGB_SRGB:			return "VK_FORMAT_BC1_RGB_SRGB";
+		case VK_FORMAT_BC1_RGBA_UNORM:			return "VK_FORMAT_BC1_RGBA_UNORM";
+		case VK_FORMAT_BC1_RGBA_SRGB:			return "VK_FORMAT_BC1_RGBA_SRGB";
+		case VK_FORMAT_BC2_UNORM:				return "VK_FORMAT_BC2_UNORM";
+		case VK_FORMAT_BC2_SRGB:				return "VK_FORMAT_BC2_SRGB";
+		case VK_FORMAT_BC3_UNORM:				return "VK_FORMAT_BC3_UNORM";
+		case VK_FORMAT_BC3_SRGB:				return "VK_FORMAT_BC3_SRGB";
+		case VK_FORMAT_BC4_UNORM:				return "VK_FORMAT_BC4_UNORM";
+		case VK_FORMAT_BC4_SNORM:				return "VK_FORMAT_BC4_SNORM";
+		case VK_FORMAT_BC5_UNORM:				return "VK_FORMAT_BC5_UNORM";
+		case VK_FORMAT_BC5_SNORM:				return "VK_FORMAT_BC5_SNORM";
+		case VK_FORMAT_BC6H_UFLOAT:				return "VK_FORMAT_BC6H_UFLOAT";
+		case VK_FORMAT_BC6H_SFLOAT:				return "VK_FORMAT_BC6H_SFLOAT";
+		case VK_FORMAT_BC7_UNORM:				return "VK_FORMAT_BC7_UNORM";
+		case VK_FORMAT_BC7_SRGB:				return "VK_FORMAT_BC7_SRGB";
+		case VK_FORMAT_ETC2_R8G8B8_UNORM:		return "VK_FORMAT_ETC2_R8G8B8_UNORM";
+		case VK_FORMAT_ETC2_R8G8B8_SRGB:		return "VK_FORMAT_ETC2_R8G8B8_SRGB";
+		case VK_FORMAT_ETC2_R8G8B8A1_UNORM:		return "VK_FORMAT_ETC2_R8G8B8A1_UNORM";
+		case VK_FORMAT_ETC2_R8G8B8A1_SRGB:		return "VK_FORMAT_ETC2_R8G8B8A1_SRGB";
+		case VK_FORMAT_ETC2_R8G8B8A8_UNORM:		return "VK_FORMAT_ETC2_R8G8B8A8_UNORM";
+		case VK_FORMAT_ETC2_R8G8B8A8_SRGB:		return "VK_FORMAT_ETC2_R8G8B8A8_SRGB";
+		case VK_FORMAT_EAC_R11_UNORM:			return "VK_FORMAT_EAC_R11_UNORM";
+		case VK_FORMAT_EAC_R11_SNORM:			return "VK_FORMAT_EAC_R11_SNORM";
+		case VK_FORMAT_EAC_R11G11_UNORM:		return "VK_FORMAT_EAC_R11G11_UNORM";
+		case VK_FORMAT_EAC_R11G11_SNORM:		return "VK_FORMAT_EAC_R11G11_SNORM";
+		case VK_FORMAT_ASTC_4x4_UNORM:			return "VK_FORMAT_ASTC_4x4_UNORM";
+		case VK_FORMAT_ASTC_4x4_SRGB:			return "VK_FORMAT_ASTC_4x4_SRGB";
+		case VK_FORMAT_ASTC_5x4_UNORM:			return "VK_FORMAT_ASTC_5x4_UNORM";
+		case VK_FORMAT_ASTC_5x4_SRGB:			return "VK_FORMAT_ASTC_5x4_SRGB";
+		case VK_FORMAT_ASTC_5x5_UNORM:			return "VK_FORMAT_ASTC_5x5_UNORM";
+		case VK_FORMAT_ASTC_5x5_SRGB:			return "VK_FORMAT_ASTC_5x5_SRGB";
+		case VK_FORMAT_ASTC_6x5_UNORM:			return "VK_FORMAT_ASTC_6x5_UNORM";
+		case VK_FORMAT_ASTC_6x5_SRGB:			return "VK_FORMAT_ASTC_6x5_SRGB";
+		case VK_FORMAT_ASTC_6x6_UNORM:			return "VK_FORMAT_ASTC_6x6_UNORM";
+		case VK_FORMAT_ASTC_6x6_SRGB:			return "VK_FORMAT_ASTC_6x6_SRGB";
+		case VK_FORMAT_ASTC_8x5_UNORM:			return "VK_FORMAT_ASTC_8x5_UNORM";
+		case VK_FORMAT_ASTC_8x5_SRGB:			return "VK_FORMAT_ASTC_8x5_SRGB";
+		case VK_FORMAT_ASTC_8x6_UNORM:			return "VK_FORMAT_ASTC_8x6_UNORM";
+		case VK_FORMAT_ASTC_8x6_SRGB:			return "VK_FORMAT_ASTC_8x6_SRGB";
+		case VK_FORMAT_ASTC_8x8_UNORM:			return "VK_FORMAT_ASTC_8x8_UNORM";
+		case VK_FORMAT_ASTC_8x8_SRGB:			return "VK_FORMAT_ASTC_8x8_SRGB";
+		case VK_FORMAT_ASTC_10x5_UNORM:			return "VK_FORMAT_ASTC_10x5_UNORM";
+		case VK_FORMAT_ASTC_10x5_SRGB:			return "VK_FORMAT_ASTC_10x5_SRGB";
+		case VK_FORMAT_ASTC_10x6_UNORM:			return "VK_FORMAT_ASTC_10x6_UNORM";
+		case VK_FORMAT_ASTC_10x6_SRGB:			return "VK_FORMAT_ASTC_10x6_SRGB";
+		case VK_FORMAT_ASTC_10x8_UNORM:			return "VK_FORMAT_ASTC_10x8_UNORM";
+		case VK_FORMAT_ASTC_10x8_SRGB:			return "VK_FORMAT_ASTC_10x8_SRGB";
+		case VK_FORMAT_ASTC_10x10_UNORM:		return "VK_FORMAT_ASTC_10x10_UNORM";
+		case VK_FORMAT_ASTC_10x10_SRGB:			return "VK_FORMAT_ASTC_10x10_SRGB";
+		case VK_FORMAT_ASTC_12x10_UNORM:		return "VK_FORMAT_ASTC_12x10_UNORM";
+		case VK_FORMAT_ASTC_12x10_SRGB:			return "VK_FORMAT_ASTC_12x10_SRGB";
+		case VK_FORMAT_ASTC_12x12_UNORM:		return "VK_FORMAT_ASTC_12x12_UNORM";
+		case VK_FORMAT_ASTC_12x12_SRGB:			return "VK_FORMAT_ASTC_12x12_SRGB";
+		case VK_FORMAT_B4G4R4A4_UNORM:			return "VK_FORMAT_B4G4R4A4_UNORM";
+		case VK_FORMAT_B5G5R5A1_UNORM:			return "VK_FORMAT_B5G5R5A1_UNORM";
+		case VK_FORMAT_B5G6R5_UNORM:			return "VK_FORMAT_B5G6R5_UNORM";
+		case VK_FORMAT_B5G6R5_USCALED:			return "VK_FORMAT_B5G6R5_USCALED";
+		case VK_FORMAT_B8G8R8_UNORM:			return "VK_FORMAT_B8G8R8_UNORM";
+		case VK_FORMAT_B8G8R8_SNORM:			return "VK_FORMAT_B8G8R8_SNORM";
+		case VK_FORMAT_B8G8R8_USCALED:			return "VK_FORMAT_B8G8R8_USCALED";
+		case VK_FORMAT_B8G8R8_SSCALED:			return "VK_FORMAT_B8G8R8_SSCALED";
+		case VK_FORMAT_B8G8R8_UINT:				return "VK_FORMAT_B8G8R8_UINT";
+		case VK_FORMAT_B8G8R8_SINT:				return "VK_FORMAT_B8G8R8_SINT";
+		case VK_FORMAT_B8G8R8_SRGB:				return "VK_FORMAT_B8G8R8_SRGB";
+		case VK_FORMAT_B8G8R8A8_UNORM:			return "VK_FORMAT_B8G8R8A8_UNORM";
+		case VK_FORMAT_B8G8R8A8_SNORM:			return "VK_FORMAT_B8G8R8A8_SNORM";
+		case VK_FORMAT_B8G8R8A8_USCALED:		return "VK_FORMAT_B8G8R8A8_USCALED";
+		case VK_FORMAT_B8G8R8A8_SSCALED:		return "VK_FORMAT_B8G8R8A8_SSCALED";
+		case VK_FORMAT_B8G8R8A8_UINT:			return "VK_FORMAT_B8G8R8A8_UINT";
+		case VK_FORMAT_B8G8R8A8_SINT:			return "VK_FORMAT_B8G8R8A8_SINT";
+		case VK_FORMAT_B8G8R8A8_SRGB:			return "VK_FORMAT_B8G8R8A8_SRGB";
+		case VK_FORMAT_B10G10R10A2_UNORM:		return "VK_FORMAT_B10G10R10A2_UNORM";
+		case VK_FORMAT_B10G10R10A2_SNORM:		return "VK_FORMAT_B10G10R10A2_SNORM";
+		case VK_FORMAT_B10G10R10A2_USCALED:		return "VK_FORMAT_B10G10R10A2_USCALED";
+		case VK_FORMAT_B10G10R10A2_SSCALED:		return "VK_FORMAT_B10G10R10A2_SSCALED";
+		case VK_FORMAT_B10G10R10A2_UINT:		return "VK_FORMAT_B10G10R10A2_UINT";
+		case VK_FORMAT_B10G10R10A2_SINT:		return "VK_FORMAT_B10G10R10A2_SINT";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getImageTypeName (VkImageType value)
+{
+	switch (value)
+	{
+		case VK_IMAGE_TYPE_1D:	return "VK_IMAGE_TYPE_1D";
+		case VK_IMAGE_TYPE_2D:	return "VK_IMAGE_TYPE_2D";
+		case VK_IMAGE_TYPE_3D:	return "VK_IMAGE_TYPE_3D";
+		default:				return DE_NULL;
+	}
+}
+
+const char* getImageTilingName (VkImageTiling value)
+{
+	switch (value)
+	{
+		case VK_IMAGE_TILING_LINEAR:	return "VK_IMAGE_TILING_LINEAR";
+		case VK_IMAGE_TILING_OPTIMAL:	return "VK_IMAGE_TILING_OPTIMAL";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getPhysicalDeviceTypeName (VkPhysicalDeviceType value)
+{
+	switch (value)
+	{
+		case VK_PHYSICAL_DEVICE_TYPE_OTHER:				return "VK_PHYSICAL_DEVICE_TYPE_OTHER";
+		case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:	return "VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU";
+		case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:		return "VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU";
+		case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:		return "VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU";
+		case VK_PHYSICAL_DEVICE_TYPE_CPU:				return "VK_PHYSICAL_DEVICE_TYPE_CPU";
+		default:										return DE_NULL;
+	}
+}
+
+const char* getImageAspectName (VkImageAspect value)
+{
+	switch (value)
+	{
+		case VK_IMAGE_ASPECT_COLOR:		return "VK_IMAGE_ASPECT_COLOR";
+		case VK_IMAGE_ASPECT_DEPTH:		return "VK_IMAGE_ASPECT_DEPTH";
+		case VK_IMAGE_ASPECT_STENCIL:	return "VK_IMAGE_ASPECT_STENCIL";
+		case VK_IMAGE_ASPECT_METADATA:	return "VK_IMAGE_ASPECT_METADATA";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getQueryTypeName (VkQueryType value)
+{
+	switch (value)
+	{
+		case VK_QUERY_TYPE_OCCLUSION:			return "VK_QUERY_TYPE_OCCLUSION";
+		case VK_QUERY_TYPE_PIPELINE_STATISTICS:	return "VK_QUERY_TYPE_PIPELINE_STATISTICS";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getSharingModeName (VkSharingMode value)
+{
+	switch (value)
+	{
+		case VK_SHARING_MODE_EXCLUSIVE:		return "VK_SHARING_MODE_EXCLUSIVE";
+		case VK_SHARING_MODE_CONCURRENT:	return "VK_SHARING_MODE_CONCURRENT";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getImageLayoutName (VkImageLayout value)
+{
+	switch (value)
+	{
+		case VK_IMAGE_LAYOUT_UNDEFINED:							return "VK_IMAGE_LAYOUT_UNDEFINED";
+		case VK_IMAGE_LAYOUT_GENERAL:							return "VK_IMAGE_LAYOUT_GENERAL";
+		case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:			return "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL";
+		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:	return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL";
+		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:	return "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL";
+		case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:			return "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL";
+		case VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL:			return "VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL";
+		case VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL:		return "VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL";
+		case VK_IMAGE_LAYOUT_PREINITIALIZED:					return "VK_IMAGE_LAYOUT_PREINITIALIZED";
+		default:												return DE_NULL;
+	}
+}
+
+const char* getImageViewTypeName (VkImageViewType value)
+{
+	switch (value)
+	{
+		case VK_IMAGE_VIEW_TYPE_1D:			return "VK_IMAGE_VIEW_TYPE_1D";
+		case VK_IMAGE_VIEW_TYPE_2D:			return "VK_IMAGE_VIEW_TYPE_2D";
+		case VK_IMAGE_VIEW_TYPE_3D:			return "VK_IMAGE_VIEW_TYPE_3D";
+		case VK_IMAGE_VIEW_TYPE_CUBE:		return "VK_IMAGE_VIEW_TYPE_CUBE";
+		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return "VK_IMAGE_VIEW_TYPE_1D_ARRAY";
+		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return "VK_IMAGE_VIEW_TYPE_2D_ARRAY";
+		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return "VK_IMAGE_VIEW_TYPE_CUBE_ARRAY";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getChannelSwizzleName (VkChannelSwizzle value)
+{
+	switch (value)
+	{
+		case VK_CHANNEL_SWIZZLE_ZERO:	return "VK_CHANNEL_SWIZZLE_ZERO";
+		case VK_CHANNEL_SWIZZLE_ONE:	return "VK_CHANNEL_SWIZZLE_ONE";
+		case VK_CHANNEL_SWIZZLE_R:		return "VK_CHANNEL_SWIZZLE_R";
+		case VK_CHANNEL_SWIZZLE_G:		return "VK_CHANNEL_SWIZZLE_G";
+		case VK_CHANNEL_SWIZZLE_B:		return "VK_CHANNEL_SWIZZLE_B";
+		case VK_CHANNEL_SWIZZLE_A:		return "VK_CHANNEL_SWIZZLE_A";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getShaderStageName (VkShaderStage value)
+{
+	switch (value)
+	{
+		case VK_SHADER_STAGE_VERTEX:			return "VK_SHADER_STAGE_VERTEX";
+		case VK_SHADER_STAGE_TESS_CONTROL:		return "VK_SHADER_STAGE_TESS_CONTROL";
+		case VK_SHADER_STAGE_TESS_EVALUATION:	return "VK_SHADER_STAGE_TESS_EVALUATION";
+		case VK_SHADER_STAGE_GEOMETRY:			return "VK_SHADER_STAGE_GEOMETRY";
+		case VK_SHADER_STAGE_FRAGMENT:			return "VK_SHADER_STAGE_FRAGMENT";
+		case VK_SHADER_STAGE_COMPUTE:			return "VK_SHADER_STAGE_COMPUTE";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getVertexInputStepRateName (VkVertexInputStepRate value)
+{
+	switch (value)
+	{
+		case VK_VERTEX_INPUT_STEP_RATE_VERTEX:		return "VK_VERTEX_INPUT_STEP_RATE_VERTEX";
+		case VK_VERTEX_INPUT_STEP_RATE_INSTANCE:	return "VK_VERTEX_INPUT_STEP_RATE_INSTANCE";
+		default:									return DE_NULL;
+	}
+}
+
+const char* getPrimitiveTopologyName (VkPrimitiveTopology value)
+{
+	switch (value)
+	{
+		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:			return "VK_PRIMITIVE_TOPOLOGY_POINT_LIST";
+		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:			return "VK_PRIMITIVE_TOPOLOGY_LINE_LIST";
+		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:			return "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP";
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:		return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST";
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:		return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP";
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:		return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN";
+		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ:		return "VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ";
+		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ:		return "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ";
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ:	return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ";
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ:	return "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ";
+		case VK_PRIMITIVE_TOPOLOGY_PATCH:				return "VK_PRIMITIVE_TOPOLOGY_PATCH";
+		default:										return DE_NULL;
+	}
+}
+
+const char* getFillModeName (VkFillMode value)
+{
+	switch (value)
+	{
+		case VK_FILL_MODE_POINTS:		return "VK_FILL_MODE_POINTS";
+		case VK_FILL_MODE_WIREFRAME:	return "VK_FILL_MODE_WIREFRAME";
+		case VK_FILL_MODE_SOLID:		return "VK_FILL_MODE_SOLID";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getCullModeName (VkCullMode value)
+{
+	switch (value)
+	{
+		case VK_CULL_MODE_NONE:				return "VK_CULL_MODE_NONE";
+		case VK_CULL_MODE_FRONT:			return "VK_CULL_MODE_FRONT";
+		case VK_CULL_MODE_BACK:				return "VK_CULL_MODE_BACK";
+		case VK_CULL_MODE_FRONT_AND_BACK:	return "VK_CULL_MODE_FRONT_AND_BACK";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getFrontFaceName (VkFrontFace value)
+{
+	switch (value)
+	{
+		case VK_FRONT_FACE_CCW:	return "VK_FRONT_FACE_CCW";
+		case VK_FRONT_FACE_CW:	return "VK_FRONT_FACE_CW";
+		default:				return DE_NULL;
+	}
+}
+
+const char* getCompareOpName (VkCompareOp value)
+{
+	switch (value)
+	{
+		case VK_COMPARE_OP_NEVER:			return "VK_COMPARE_OP_NEVER";
+		case VK_COMPARE_OP_LESS:			return "VK_COMPARE_OP_LESS";
+		case VK_COMPARE_OP_EQUAL:			return "VK_COMPARE_OP_EQUAL";
+		case VK_COMPARE_OP_LESS_EQUAL:		return "VK_COMPARE_OP_LESS_EQUAL";
+		case VK_COMPARE_OP_GREATER:			return "VK_COMPARE_OP_GREATER";
+		case VK_COMPARE_OP_NOT_EQUAL:		return "VK_COMPARE_OP_NOT_EQUAL";
+		case VK_COMPARE_OP_GREATER_EQUAL:	return "VK_COMPARE_OP_GREATER_EQUAL";
+		case VK_COMPARE_OP_ALWAYS:			return "VK_COMPARE_OP_ALWAYS";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getStencilOpName (VkStencilOp value)
+{
+	switch (value)
+	{
+		case VK_STENCIL_OP_KEEP:		return "VK_STENCIL_OP_KEEP";
+		case VK_STENCIL_OP_ZERO:		return "VK_STENCIL_OP_ZERO";
+		case VK_STENCIL_OP_REPLACE:		return "VK_STENCIL_OP_REPLACE";
+		case VK_STENCIL_OP_INC_CLAMP:	return "VK_STENCIL_OP_INC_CLAMP";
+		case VK_STENCIL_OP_DEC_CLAMP:	return "VK_STENCIL_OP_DEC_CLAMP";
+		case VK_STENCIL_OP_INVERT:		return "VK_STENCIL_OP_INVERT";
+		case VK_STENCIL_OP_INC_WRAP:	return "VK_STENCIL_OP_INC_WRAP";
+		case VK_STENCIL_OP_DEC_WRAP:	return "VK_STENCIL_OP_DEC_WRAP";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getLogicOpName (VkLogicOp value)
+{
+	switch (value)
+	{
+		case VK_LOGIC_OP_CLEAR:			return "VK_LOGIC_OP_CLEAR";
+		case VK_LOGIC_OP_AND:			return "VK_LOGIC_OP_AND";
+		case VK_LOGIC_OP_AND_REVERSE:	return "VK_LOGIC_OP_AND_REVERSE";
+		case VK_LOGIC_OP_COPY:			return "VK_LOGIC_OP_COPY";
+		case VK_LOGIC_OP_AND_INVERTED:	return "VK_LOGIC_OP_AND_INVERTED";
+		case VK_LOGIC_OP_NOOP:			return "VK_LOGIC_OP_NOOP";
+		case VK_LOGIC_OP_XOR:			return "VK_LOGIC_OP_XOR";
+		case VK_LOGIC_OP_OR:			return "VK_LOGIC_OP_OR";
+		case VK_LOGIC_OP_NOR:			return "VK_LOGIC_OP_NOR";
+		case VK_LOGIC_OP_EQUIV:			return "VK_LOGIC_OP_EQUIV";
+		case VK_LOGIC_OP_INVERT:		return "VK_LOGIC_OP_INVERT";
+		case VK_LOGIC_OP_OR_REVERSE:	return "VK_LOGIC_OP_OR_REVERSE";
+		case VK_LOGIC_OP_COPY_INVERTED:	return "VK_LOGIC_OP_COPY_INVERTED";
+		case VK_LOGIC_OP_OR_INVERTED:	return "VK_LOGIC_OP_OR_INVERTED";
+		case VK_LOGIC_OP_NAND:			return "VK_LOGIC_OP_NAND";
+		case VK_LOGIC_OP_SET:			return "VK_LOGIC_OP_SET";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getBlendName (VkBlend value)
+{
+	switch (value)
+	{
+		case VK_BLEND_ZERO:						return "VK_BLEND_ZERO";
+		case VK_BLEND_ONE:						return "VK_BLEND_ONE";
+		case VK_BLEND_SRC_COLOR:				return "VK_BLEND_SRC_COLOR";
+		case VK_BLEND_ONE_MINUS_SRC_COLOR:		return "VK_BLEND_ONE_MINUS_SRC_COLOR";
+		case VK_BLEND_DEST_COLOR:				return "VK_BLEND_DEST_COLOR";
+		case VK_BLEND_ONE_MINUS_DEST_COLOR:		return "VK_BLEND_ONE_MINUS_DEST_COLOR";
+		case VK_BLEND_SRC_ALPHA:				return "VK_BLEND_SRC_ALPHA";
+		case VK_BLEND_ONE_MINUS_SRC_ALPHA:		return "VK_BLEND_ONE_MINUS_SRC_ALPHA";
+		case VK_BLEND_DEST_ALPHA:				return "VK_BLEND_DEST_ALPHA";
+		case VK_BLEND_ONE_MINUS_DEST_ALPHA:		return "VK_BLEND_ONE_MINUS_DEST_ALPHA";
+		case VK_BLEND_CONSTANT_COLOR:			return "VK_BLEND_CONSTANT_COLOR";
+		case VK_BLEND_ONE_MINUS_CONSTANT_COLOR:	return "VK_BLEND_ONE_MINUS_CONSTANT_COLOR";
+		case VK_BLEND_CONSTANT_ALPHA:			return "VK_BLEND_CONSTANT_ALPHA";
+		case VK_BLEND_ONE_MINUS_CONSTANT_ALPHA:	return "VK_BLEND_ONE_MINUS_CONSTANT_ALPHA";
+		case VK_BLEND_SRC_ALPHA_SATURATE:		return "VK_BLEND_SRC_ALPHA_SATURATE";
+		case VK_BLEND_SRC1_COLOR:				return "VK_BLEND_SRC1_COLOR";
+		case VK_BLEND_ONE_MINUS_SRC1_COLOR:		return "VK_BLEND_ONE_MINUS_SRC1_COLOR";
+		case VK_BLEND_SRC1_ALPHA:				return "VK_BLEND_SRC1_ALPHA";
+		case VK_BLEND_ONE_MINUS_SRC1_ALPHA:		return "VK_BLEND_ONE_MINUS_SRC1_ALPHA";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getBlendOpName (VkBlendOp value)
+{
+	switch (value)
+	{
+		case VK_BLEND_OP_ADD:				return "VK_BLEND_OP_ADD";
+		case VK_BLEND_OP_SUBTRACT:			return "VK_BLEND_OP_SUBTRACT";
+		case VK_BLEND_OP_REVERSE_SUBTRACT:	return "VK_BLEND_OP_REVERSE_SUBTRACT";
+		case VK_BLEND_OP_MIN:				return "VK_BLEND_OP_MIN";
+		case VK_BLEND_OP_MAX:				return "VK_BLEND_OP_MAX";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getDynamicStateName (VkDynamicState value)
+{
+	switch (value)
+	{
+		case VK_DYNAMIC_STATE_VIEWPORT:				return "VK_DYNAMIC_STATE_VIEWPORT";
+		case VK_DYNAMIC_STATE_SCISSOR:				return "VK_DYNAMIC_STATE_SCISSOR";
+		case VK_DYNAMIC_STATE_LINE_WIDTH:			return "VK_DYNAMIC_STATE_LINE_WIDTH";
+		case VK_DYNAMIC_STATE_DEPTH_BIAS:			return "VK_DYNAMIC_STATE_DEPTH_BIAS";
+		case VK_DYNAMIC_STATE_BLEND_CONSTANTS:		return "VK_DYNAMIC_STATE_BLEND_CONSTANTS";
+		case VK_DYNAMIC_STATE_DEPTH_BOUNDS:			return "VK_DYNAMIC_STATE_DEPTH_BOUNDS";
+		case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:	return "VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK";
+		case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:	return "VK_DYNAMIC_STATE_STENCIL_WRITE_MASK";
+		case VK_DYNAMIC_STATE_STENCIL_REFERENCE:	return "VK_DYNAMIC_STATE_STENCIL_REFERENCE";
+		default:									return DE_NULL;
+	}
+}
+
+const char* getTexFilterName (VkTexFilter value)
+{
+	switch (value)
+	{
+		case VK_TEX_FILTER_NEAREST:	return "VK_TEX_FILTER_NEAREST";
+		case VK_TEX_FILTER_LINEAR:	return "VK_TEX_FILTER_LINEAR";
+		default:					return DE_NULL;
+	}
+}
+
+const char* getTexMipmapModeName (VkTexMipmapMode value)
+{
+	switch (value)
+	{
+		case VK_TEX_MIPMAP_MODE_BASE:		return "VK_TEX_MIPMAP_MODE_BASE";
+		case VK_TEX_MIPMAP_MODE_NEAREST:	return "VK_TEX_MIPMAP_MODE_NEAREST";
+		case VK_TEX_MIPMAP_MODE_LINEAR:		return "VK_TEX_MIPMAP_MODE_LINEAR";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getTexAddressModeName (VkTexAddressMode value)
+{
+	switch (value)
+	{
+		case VK_TEX_ADDRESS_MODE_WRAP:			return "VK_TEX_ADDRESS_MODE_WRAP";
+		case VK_TEX_ADDRESS_MODE_MIRROR:		return "VK_TEX_ADDRESS_MODE_MIRROR";
+		case VK_TEX_ADDRESS_MODE_CLAMP:			return "VK_TEX_ADDRESS_MODE_CLAMP";
+		case VK_TEX_ADDRESS_MODE_MIRROR_ONCE:	return "VK_TEX_ADDRESS_MODE_MIRROR_ONCE";
+		case VK_TEX_ADDRESS_MODE_CLAMP_BORDER:	return "VK_TEX_ADDRESS_MODE_CLAMP_BORDER";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getBorderColorName (VkBorderColor value)
+{
+	switch (value)
+	{
+		case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:	return "VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK";
+		case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:		return "VK_BORDER_COLOR_INT_TRANSPARENT_BLACK";
+		case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:		return "VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK";
+		case VK_BORDER_COLOR_INT_OPAQUE_BLACK:			return "VK_BORDER_COLOR_INT_OPAQUE_BLACK";
+		case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:		return "VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE";
+		case VK_BORDER_COLOR_INT_OPAQUE_WHITE:			return "VK_BORDER_COLOR_INT_OPAQUE_WHITE";
+		default:										return DE_NULL;
+	}
+}
+
+const char* getDescriptorTypeName (VkDescriptorType value)
+{
+	switch (value)
+	{
+		case VK_DESCRIPTOR_TYPE_SAMPLER:				return "VK_DESCRIPTOR_TYPE_SAMPLER";
+		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:	return "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER";
+		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:			return "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE";
+		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:			return "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE";
+		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:	return "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER";
+		case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:	return "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER";
+		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:			return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER";
+		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:			return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER";
+		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:	return "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC";
+		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:	return "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC";
+		case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:		return "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT";
+		default:										return DE_NULL;
+	}
+}
+
+const char* getDescriptorPoolUsageName (VkDescriptorPoolUsage value)
+{
+	switch (value)
+	{
+		case VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT:	return "VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT";
+		case VK_DESCRIPTOR_POOL_USAGE_DYNAMIC:	return "VK_DESCRIPTOR_POOL_USAGE_DYNAMIC";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getDescriptorSetUsageName (VkDescriptorSetUsage value)
+{
+	switch (value)
+	{
+		case VK_DESCRIPTOR_SET_USAGE_ONE_SHOT:	return "VK_DESCRIPTOR_SET_USAGE_ONE_SHOT";
+		case VK_DESCRIPTOR_SET_USAGE_STATIC:	return "VK_DESCRIPTOR_SET_USAGE_STATIC";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getAttachmentLoadOpName (VkAttachmentLoadOp value)
+{
+	switch (value)
+	{
+		case VK_ATTACHMENT_LOAD_OP_LOAD:		return "VK_ATTACHMENT_LOAD_OP_LOAD";
+		case VK_ATTACHMENT_LOAD_OP_CLEAR:		return "VK_ATTACHMENT_LOAD_OP_CLEAR";
+		case VK_ATTACHMENT_LOAD_OP_DONT_CARE:	return "VK_ATTACHMENT_LOAD_OP_DONT_CARE";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getAttachmentStoreOpName (VkAttachmentStoreOp value)
+{
+	switch (value)
+	{
+		case VK_ATTACHMENT_STORE_OP_STORE:		return "VK_ATTACHMENT_STORE_OP_STORE";
+		case VK_ATTACHMENT_STORE_OP_DONT_CARE:	return "VK_ATTACHMENT_STORE_OP_DONT_CARE";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getPipelineBindPointName (VkPipelineBindPoint value)
+{
+	switch (value)
+	{
+		case VK_PIPELINE_BIND_POINT_COMPUTE:	return "VK_PIPELINE_BIND_POINT_COMPUTE";
+		case VK_PIPELINE_BIND_POINT_GRAPHICS:	return "VK_PIPELINE_BIND_POINT_GRAPHICS";
+		default:								return DE_NULL;
+	}
+}
+
+const char* getCmdBufferLevelName (VkCmdBufferLevel value)
+{
+	switch (value)
+	{
+		case VK_CMD_BUFFER_LEVEL_PRIMARY:	return "VK_CMD_BUFFER_LEVEL_PRIMARY";
+		case VK_CMD_BUFFER_LEVEL_SECONDARY:	return "VK_CMD_BUFFER_LEVEL_SECONDARY";
+		default:							return DE_NULL;
+	}
+}
+
+const char* getIndexTypeName (VkIndexType value)
+{
+	switch (value)
+	{
+		case VK_INDEX_TYPE_UINT16:	return "VK_INDEX_TYPE_UINT16";
+		case VK_INDEX_TYPE_UINT32:	return "VK_INDEX_TYPE_UINT32";
+		default:					return DE_NULL;
+	}
+}
+
+const char* getTimestampTypeName (VkTimestampType value)
+{
+	switch (value)
+	{
+		case VK_TIMESTAMP_TYPE_TOP:		return "VK_TIMESTAMP_TYPE_TOP";
+		case VK_TIMESTAMP_TYPE_BOTTOM:	return "VK_TIMESTAMP_TYPE_BOTTOM";
+		default:						return DE_NULL;
+	}
+}
+
+const char* getRenderPassContentsName (VkRenderPassContents value)
+{
+	switch (value)
+	{
+		case VK_RENDER_PASS_CONTENTS_INLINE:				return "VK_RENDER_PASS_CONTENTS_INLINE";
+		case VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS:	return "VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS";
+		default:											return DE_NULL;
+	}
+}
+
+tcu::Format::Bitfield<32> getFormatFeatureFlagsStr (VkFormatFeatureFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,				"VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,				"VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT,		"VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT,		"VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT,		"VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT,	"VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,				"VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,			"VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT,		"VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,	"VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_BLIT_SOURCE_BIT,					"VK_FORMAT_FEATURE_BLIT_SOURCE_BIT"),
+		tcu::Format::BitDesc(VK_FORMAT_FEATURE_BLIT_DESTINATION_BIT,			"VK_FORMAT_FEATURE_BLIT_DESTINATION_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getImageUsageFlagsStr (VkImageUsageFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,			"VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT,		"VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_SAMPLED_BIT,					"VK_IMAGE_USAGE_SAMPLED_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_STORAGE_BIT,					"VK_IMAGE_USAGE_STORAGE_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,			"VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,	"VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,		"VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,			"VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getImageCreateFlagsStr (VkImageCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_IMAGE_CREATE_SPARSE_BINDING_BIT,	"VK_IMAGE_CREATE_SPARSE_BINDING_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT,	"VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,	"VK_IMAGE_CREATE_SPARSE_ALIASED_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,	"VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,	"VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getSampleCountFlagsStr (VkSampleCountFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_1_BIT,		"VK_SAMPLE_COUNT_1_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_2_BIT,		"VK_SAMPLE_COUNT_2_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_4_BIT,		"VK_SAMPLE_COUNT_4_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_8_BIT,		"VK_SAMPLE_COUNT_8_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_16_BIT,	"VK_SAMPLE_COUNT_16_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_32_BIT,	"VK_SAMPLE_COUNT_32_BIT"),
+		tcu::Format::BitDesc(VK_SAMPLE_COUNT_64_BIT,	"VK_SAMPLE_COUNT_64_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getQueueFlagsStr (VkQueueFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_QUEUE_GRAPHICS_BIT,			"VK_QUEUE_GRAPHICS_BIT"),
+		tcu::Format::BitDesc(VK_QUEUE_COMPUTE_BIT,			"VK_QUEUE_COMPUTE_BIT"),
+		tcu::Format::BitDesc(VK_QUEUE_DMA_BIT,				"VK_QUEUE_DMA_BIT"),
+		tcu::Format::BitDesc(VK_QUEUE_SPARSE_MEMMGR_BIT,	"VK_QUEUE_SPARSE_MEMMGR_BIT"),
+		tcu::Format::BitDesc(VK_QUEUE_EXTENDED_BIT,			"VK_QUEUE_EXTENDED_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getMemoryPropertyFlagsStr (VkMemoryPropertyFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_DEVICE_ONLY,				"VK_MEMORY_PROPERTY_DEVICE_ONLY"),
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,			"VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_HOST_NON_COHERENT_BIT,		"VK_MEMORY_PROPERTY_HOST_NON_COHERENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT,			"VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT,	"VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,		"VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getMemoryHeapFlagsStr (VkMemoryHeapFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_MEMORY_HEAP_HOST_LOCAL_BIT,	"VK_MEMORY_HEAP_HOST_LOCAL_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getSparseImageFormatFlagsStr (VkSparseImageFormatFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_SPARSE_IMAGE_FMT_SINGLE_MIPTAIL_BIT,	"VK_SPARSE_IMAGE_FMT_SINGLE_MIPTAIL_BIT"),
+		tcu::Format::BitDesc(VK_SPARSE_IMAGE_FMT_ALIGNED_MIP_SIZE_BIT,	"VK_SPARSE_IMAGE_FMT_ALIGNED_MIP_SIZE_BIT"),
+		tcu::Format::BitDesc(VK_SPARSE_IMAGE_FMT_NONSTD_BLOCK_SIZE_BIT,	"VK_SPARSE_IMAGE_FMT_NONSTD_BLOCK_SIZE_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getSparseMemoryBindFlagsStr (VkSparseMemoryBindFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_SPARSE_MEMORY_BIND_REPLICATE_64KIB_BLOCK_BIT,	"VK_SPARSE_MEMORY_BIND_REPLICATE_64KIB_BLOCK_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getFenceCreateFlagsStr (VkFenceCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_FENCE_CREATE_SIGNALED_BIT,	"VK_FENCE_CREATE_SIGNALED_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getQueryPipelineStatisticFlagsStr (VkQueryPipelineStatisticFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_IA_VERTICES_BIT,		"VK_QUERY_PIPELINE_STATISTIC_IA_VERTICES_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_IA_PRIMITIVES_BIT,		"VK_QUERY_PIPELINE_STATISTIC_IA_PRIMITIVES_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_VS_INVOCATIONS_BIT,	"VK_QUERY_PIPELINE_STATISTIC_VS_INVOCATIONS_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_GS_INVOCATIONS_BIT,	"VK_QUERY_PIPELINE_STATISTIC_GS_INVOCATIONS_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_GS_PRIMITIVES_BIT,		"VK_QUERY_PIPELINE_STATISTIC_GS_PRIMITIVES_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_C_INVOCATIONS_BIT,		"VK_QUERY_PIPELINE_STATISTIC_C_INVOCATIONS_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_C_PRIMITIVES_BIT,		"VK_QUERY_PIPELINE_STATISTIC_C_PRIMITIVES_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_FS_INVOCATIONS_BIT,	"VK_QUERY_PIPELINE_STATISTIC_FS_INVOCATIONS_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_TCS_PATCHES_BIT,		"VK_QUERY_PIPELINE_STATISTIC_TCS_PATCHES_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_TES_INVOCATIONS_BIT,	"VK_QUERY_PIPELINE_STATISTIC_TES_INVOCATIONS_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_PIPELINE_STATISTIC_CS_INVOCATIONS_BIT,	"VK_QUERY_PIPELINE_STATISTIC_CS_INVOCATIONS_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getQueryResultFlagsStr (VkQueryResultFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_QUERY_RESULT_DEFAULT,				"VK_QUERY_RESULT_DEFAULT"),
+		tcu::Format::BitDesc(VK_QUERY_RESULT_64_BIT,				"VK_QUERY_RESULT_64_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_RESULT_WAIT_BIT,				"VK_QUERY_RESULT_WAIT_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_RESULT_WITH_AVAILABILITY_BIT,	"VK_QUERY_RESULT_WITH_AVAILABILITY_BIT"),
+		tcu::Format::BitDesc(VK_QUERY_RESULT_PARTIAL_BIT,			"VK_QUERY_RESULT_PARTIAL_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getBufferUsageFlagsStr (VkBufferUsageFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT,		"VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,	"VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,	"VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,	"VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,		"VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		"VK_BUFFER_USAGE_STORAGE_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_INDEX_BUFFER_BIT,			"VK_BUFFER_USAGE_INDEX_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			"VK_BUFFER_USAGE_VERTEX_BUFFER_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,		"VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getBufferCreateFlagsStr (VkBufferCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_BUFFER_CREATE_SPARSE_BINDING_BIT,	"VK_BUFFER_CREATE_SPARSE_BINDING_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,	"VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT"),
+		tcu::Format::BitDesc(VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,	"VK_BUFFER_CREATE_SPARSE_ALIASED_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getImageAspectFlagsStr (VkImageAspectFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_IMAGE_ASPECT_COLOR_BIT,		"VK_IMAGE_ASPECT_COLOR_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_ASPECT_DEPTH_BIT,		"VK_IMAGE_ASPECT_DEPTH_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_ASPECT_STENCIL_BIT,	"VK_IMAGE_ASPECT_STENCIL_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_ASPECT_METADATA_BIT,	"VK_IMAGE_ASPECT_METADATA_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getImageViewCreateFlagsStr (VkImageViewCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_IMAGE_VIEW_CREATE_READ_ONLY_DEPTH_BIT,		"VK_IMAGE_VIEW_CREATE_READ_ONLY_DEPTH_BIT"),
+		tcu::Format::BitDesc(VK_IMAGE_VIEW_CREATE_READ_ONLY_STENCIL_BIT,	"VK_IMAGE_VIEW_CREATE_READ_ONLY_STENCIL_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getChannelFlagsStr (VkChannelFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_CHANNEL_R_BIT,	"VK_CHANNEL_R_BIT"),
+		tcu::Format::BitDesc(VK_CHANNEL_G_BIT,	"VK_CHANNEL_G_BIT"),
+		tcu::Format::BitDesc(VK_CHANNEL_B_BIT,	"VK_CHANNEL_B_BIT"),
+		tcu::Format::BitDesc(VK_CHANNEL_A_BIT,	"VK_CHANNEL_A_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getPipelineCreateFlagsStr (VkPipelineCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,	"VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT,		"VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_CREATE_DERIVATIVE_BIT,				"VK_PIPELINE_CREATE_DERIVATIVE_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getShaderStageFlagsStr (VkShaderStageFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_SHADER_STAGE_VERTEX_BIT,			"VK_SHADER_STAGE_VERTEX_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_TESS_CONTROL_BIT,		"VK_SHADER_STAGE_TESS_CONTROL_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_TESS_EVALUATION_BIT,	"VK_SHADER_STAGE_TESS_EVALUATION_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_GEOMETRY_BIT,			"VK_SHADER_STAGE_GEOMETRY_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_FRAGMENT_BIT,			"VK_SHADER_STAGE_FRAGMENT_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_COMPUTE_BIT,			"VK_SHADER_STAGE_COMPUTE_BIT"),
+		tcu::Format::BitDesc(VK_SHADER_STAGE_ALL,					"VK_SHADER_STAGE_ALL"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getAttachmentDescriptionFlagsStr (VkAttachmentDescriptionFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,	"VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getSubpassDescriptionFlagsStr (VkSubpassDescriptionFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_SUBPASS_DESCRIPTION_NO_OVERDRAW_BIT,	"VK_SUBPASS_DESCRIPTION_NO_OVERDRAW_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getPipelineStageFlagsStr (VkPipelineStageFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,				"VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,			"VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,			"VK_PIPELINE_STAGE_VERTEX_INPUT_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,			"VK_PIPELINE_STAGE_VERTEX_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_TESS_CONTROL_SHADER_BIT,		"VK_PIPELINE_STAGE_TESS_CONTROL_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_TESS_EVALUATION_SHADER_BIT,	"VK_PIPELINE_STAGE_TESS_EVALUATION_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,			"VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			"VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,	"VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,		"VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	"VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,			"VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_TRANSFER_BIT,				"VK_PIPELINE_STAGE_TRANSFER_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_HOST_BIT,					"VK_PIPELINE_STAGE_HOST_BIT"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_ALL_GRAPHICS,				"VK_PIPELINE_STAGE_ALL_GRAPHICS"),
+		tcu::Format::BitDesc(VK_PIPELINE_STAGE_ALL_GPU_COMMANDS,			"VK_PIPELINE_STAGE_ALL_GPU_COMMANDS"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getMemoryOutputFlagsStr (VkMemoryOutputFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_MEMORY_OUTPUT_HOST_WRITE_BIT,				"VK_MEMORY_OUTPUT_HOST_WRITE_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_OUTPUT_SHADER_WRITE_BIT,				"VK_MEMORY_OUTPUT_SHADER_WRITE_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,			"VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_OUTPUT_DEPTH_STENCIL_ATTACHMENT_BIT,	"VK_MEMORY_OUTPUT_DEPTH_STENCIL_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_OUTPUT_TRANSFER_BIT,					"VK_MEMORY_OUTPUT_TRANSFER_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getMemoryInputFlagsStr (VkMemoryInputFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_HOST_READ_BIT,					"VK_MEMORY_INPUT_HOST_READ_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_INDIRECT_COMMAND_BIT,			"VK_MEMORY_INPUT_INDIRECT_COMMAND_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_INDEX_FETCH_BIT,				"VK_MEMORY_INPUT_INDEX_FETCH_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT,	"VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_UNIFORM_READ_BIT,				"VK_MEMORY_INPUT_UNIFORM_READ_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_SHADER_READ_BIT,				"VK_MEMORY_INPUT_SHADER_READ_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT,			"VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_DEPTH_STENCIL_ATTACHMENT_BIT,	"VK_MEMORY_INPUT_DEPTH_STENCIL_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_INPUT_ATTACHMENT_BIT,			"VK_MEMORY_INPUT_INPUT_ATTACHMENT_BIT"),
+		tcu::Format::BitDesc(VK_MEMORY_INPUT_TRANSFER_BIT,					"VK_MEMORY_INPUT_TRANSFER_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getCmdPoolCreateFlagsStr (VkCmdPoolCreateFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_CMD_POOL_CREATE_TRANSIENT_BIT,				"VK_CMD_POOL_CREATE_TRANSIENT_BIT"),
+		tcu::Format::BitDesc(VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,	"VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getCmdPoolResetFlagsStr (VkCmdPoolResetFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_CMD_POOL_RESET_RELEASE_RESOURCES_BIT,	"VK_CMD_POOL_RESET_RELEASE_RESOURCES_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getCmdBufferOptimizeFlagsStr (VkCmdBufferOptimizeFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT,			"VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT"),
+		tcu::Format::BitDesc(VK_CMD_BUFFER_OPTIMIZE_PIPELINE_SWITCH_BIT,		"VK_CMD_BUFFER_OPTIMIZE_PIPELINE_SWITCH_BIT"),
+		tcu::Format::BitDesc(VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,		"VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT"),
+		tcu::Format::BitDesc(VK_CMD_BUFFER_OPTIMIZE_DESCRIPTOR_SET_SWITCH_BIT,	"VK_CMD_BUFFER_OPTIMIZE_DESCRIPTOR_SET_SWITCH_BIT"),
+		tcu::Format::BitDesc(VK_CMD_BUFFER_OPTIMIZE_NO_SIMULTANEOUS_USE_BIT,	"VK_CMD_BUFFER_OPTIMIZE_NO_SIMULTANEOUS_USE_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getCmdBufferResetFlagsStr (VkCmdBufferResetFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_CMD_BUFFER_RESET_RELEASE_RESOURCES_BIT,	"VK_CMD_BUFFER_RESET_RELEASE_RESOURCES_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getStencilFaceFlagsStr (VkStencilFaceFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_STENCIL_FACE_NONE,		"VK_STENCIL_FACE_NONE"),
+		tcu::Format::BitDesc(VK_STENCIL_FACE_FRONT_BIT,	"VK_STENCIL_FACE_FRONT_BIT"),
+		tcu::Format::BitDesc(VK_STENCIL_FACE_BACK_BIT,	"VK_STENCIL_FACE_BACK_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+tcu::Format::Bitfield<32> getQueryControlFlagsStr (VkQueryControlFlags value)
+{
+	static const tcu::Format::BitDesc s_desc[] =
+	{
+		tcu::Format::BitDesc(VK_QUERY_CONTROL_CONSERVATIVE_BIT,	"VK_QUERY_CONTROL_CONSERVATIVE_BIT"),
+	};
+	return tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));
+}
+
+std::ostream& operator<< (std::ostream& s, const VkApplicationInfo& value)
+{
+	s << "VkApplicationInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tpAppName = " << getCharPtrStr(value.pAppName) << '\n';
+	s << "\tappVersion = " << value.appVersion << '\n';
+	s << "\tpEngineName = " << getCharPtrStr(value.pEngineName) << '\n';
+	s << "\tengineVersion = " << value.engineVersion << '\n';
+	s << "\tapiVersion = " << value.apiVersion << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkAllocCallbacks& value)
+{
+	s << "VkAllocCallbacks = {\n";
+	s << "\tpUserData = " << value.pUserData << '\n';
+	s << "\tpfnAlloc = " << value.pfnAlloc << '\n';
+	s << "\tpfnFree = " << value.pfnFree << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkInstanceCreateInfo& value)
+{
+	s << "VkInstanceCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tpAppInfo = " << value.pAppInfo << '\n';
+	s << "\tpAllocCb = " << value.pAllocCb << '\n';
+	s << "\tlayerCount = " << value.layerCount << '\n';
+	s << "\tppEnabledLayerNames = " << value.ppEnabledLayerNames << '\n';
+	s << "\textensionCount = " << value.extensionCount << '\n';
+	s << "\tppEnabledExtensionNames = " << value.ppEnabledExtensionNames << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDeviceFeatures& value)
+{
+	s << "VkPhysicalDeviceFeatures = {\n";
+	s << "\trobustBufferAccess = " << value.robustBufferAccess << '\n';
+	s << "\tfullDrawIndexUint32 = " << value.fullDrawIndexUint32 << '\n';
+	s << "\timageCubeArray = " << value.imageCubeArray << '\n';
+	s << "\tindependentBlend = " << value.independentBlend << '\n';
+	s << "\tgeometryShader = " << value.geometryShader << '\n';
+	s << "\ttessellationShader = " << value.tessellationShader << '\n';
+	s << "\tsampleRateShading = " << value.sampleRateShading << '\n';
+	s << "\tdualSourceBlend = " << value.dualSourceBlend << '\n';
+	s << "\tlogicOp = " << value.logicOp << '\n';
+	s << "\tmultiDrawIndirect = " << value.multiDrawIndirect << '\n';
+	s << "\tdepthClip = " << value.depthClip << '\n';
+	s << "\tdepthBiasClamp = " << value.depthBiasClamp << '\n';
+	s << "\tfillModeNonSolid = " << value.fillModeNonSolid << '\n';
+	s << "\tdepthBounds = " << value.depthBounds << '\n';
+	s << "\twideLines = " << value.wideLines << '\n';
+	s << "\tlargePoints = " << value.largePoints << '\n';
+	s << "\ttextureCompressionETC2 = " << value.textureCompressionETC2 << '\n';
+	s << "\ttextureCompressionASTC_LDR = " << value.textureCompressionASTC_LDR << '\n';
+	s << "\ttextureCompressionBC = " << value.textureCompressionBC << '\n';
+	s << "\tocclusionQueryNonConservative = " << value.occlusionQueryNonConservative << '\n';
+	s << "\tpipelineStatisticsQuery = " << value.pipelineStatisticsQuery << '\n';
+	s << "\tvertexSideEffects = " << value.vertexSideEffects << '\n';
+	s << "\ttessellationSideEffects = " << value.tessellationSideEffects << '\n';
+	s << "\tgeometrySideEffects = " << value.geometrySideEffects << '\n';
+	s << "\tfragmentSideEffects = " << value.fragmentSideEffects << '\n';
+	s << "\tshaderTessellationPointSize = " << value.shaderTessellationPointSize << '\n';
+	s << "\tshaderGeometryPointSize = " << value.shaderGeometryPointSize << '\n';
+	s << "\tshaderImageGatherExtended = " << value.shaderImageGatherExtended << '\n';
+	s << "\tshaderStorageImageExtendedFormats = " << value.shaderStorageImageExtendedFormats << '\n';
+	s << "\tshaderStorageImageMultisample = " << value.shaderStorageImageMultisample << '\n';
+	s << "\tshaderUniformBufferArrayDynamicIndexing = " << value.shaderUniformBufferArrayDynamicIndexing << '\n';
+	s << "\tshaderSampledImageArrayDynamicIndexing = " << value.shaderSampledImageArrayDynamicIndexing << '\n';
+	s << "\tshaderStorageBufferArrayDynamicIndexing = " << value.shaderStorageBufferArrayDynamicIndexing << '\n';
+	s << "\tshaderStorageImageArrayDynamicIndexing = " << value.shaderStorageImageArrayDynamicIndexing << '\n';
+	s << "\tshaderClipDistance = " << value.shaderClipDistance << '\n';
+	s << "\tshaderCullDistance = " << value.shaderCullDistance << '\n';
+	s << "\tshaderFloat64 = " << value.shaderFloat64 << '\n';
+	s << "\tshaderInt64 = " << value.shaderInt64 << '\n';
+	s << "\tshaderInt16 = " << value.shaderInt16 << '\n';
+	s << "\tshaderResourceResidency = " << value.shaderResourceResidency << '\n';
+	s << "\tshaderResourceMinLOD = " << value.shaderResourceMinLOD << '\n';
+	s << "\talphaToOne = " << value.alphaToOne << '\n';
+	s << "\tsparseBinding = " << value.sparseBinding << '\n';
+	s << "\tsparseResidencyBuffer = " << value.sparseResidencyBuffer << '\n';
+	s << "\tsparseResidencyImage2D = " << value.sparseResidencyImage2D << '\n';
+	s << "\tsparseResidencyImage3D = " << value.sparseResidencyImage3D << '\n';
+	s << "\tsparseResidency2Samples = " << value.sparseResidency2Samples << '\n';
+	s << "\tsparseResidency4Samples = " << value.sparseResidency4Samples << '\n';
+	s << "\tsparseResidency8Samples = " << value.sparseResidency8Samples << '\n';
+	s << "\tsparseResidency16Samples = " << value.sparseResidency16Samples << '\n';
+	s << "\tsparseResidencyAliased = " << value.sparseResidencyAliased << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkFormatProperties& value)
+{
+	s << "VkFormatProperties = {\n";
+	s << "\tlinearTilingFeatures = " << getFormatFeatureFlagsStr(value.linearTilingFeatures) << '\n';
+	s << "\toptimalTilingFeatures = " << getFormatFeatureFlagsStr(value.optimalTilingFeatures) << '\n';
+	s << "\tbufferFeatures = " << getFormatFeatureFlagsStr(value.bufferFeatures) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkExtent3D& value)
+{
+	s << "VkExtent3D = {\n";
+	s << "\twidth = " << value.width << '\n';
+	s << "\theight = " << value.height << '\n';
+	s << "\tdepth = " << value.depth << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageFormatProperties& value)
+{
+	s << "VkImageFormatProperties = {\n";
+	s << "\tmaxExtent = " << value.maxExtent << '\n';
+	s << "\tmaxMipLevels = " << value.maxMipLevels << '\n';
+	s << "\tmaxArraySize = " << value.maxArraySize << '\n';
+	s << "\tsampleCounts = " << getSampleCountFlagsStr(value.sampleCounts) << '\n';
+	s << "\tmaxResourceSize = " << value.maxResourceSize << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDeviceLimits& value)
+{
+	s << "VkPhysicalDeviceLimits = {\n";
+	s << "\tmaxImageDimension1D = " << value.maxImageDimension1D << '\n';
+	s << "\tmaxImageDimension2D = " << value.maxImageDimension2D << '\n';
+	s << "\tmaxImageDimension3D = " << value.maxImageDimension3D << '\n';
+	s << "\tmaxImageDimensionCube = " << value.maxImageDimensionCube << '\n';
+	s << "\tmaxImageArrayLayers = " << value.maxImageArrayLayers << '\n';
+	s << "\tsampleCounts = " << getSampleCountFlagsStr(value.sampleCounts) << '\n';
+	s << "\tmaxTexelBufferSize = " << value.maxTexelBufferSize << '\n';
+	s << "\tmaxUniformBufferSize = " << value.maxUniformBufferSize << '\n';
+	s << "\tmaxStorageBufferSize = " << value.maxStorageBufferSize << '\n';
+	s << "\tmaxPushConstantsSize = " << value.maxPushConstantsSize << '\n';
+	s << "\tmaxMemoryAllocationCount = " << value.maxMemoryAllocationCount << '\n';
+	s << "\tbufferImageGranularity = " << value.bufferImageGranularity << '\n';
+	s << "\tsparseAddressSpaceSize = " << value.sparseAddressSpaceSize << '\n';
+	s << "\tmaxBoundDescriptorSets = " << value.maxBoundDescriptorSets << '\n';
+	s << "\tmaxDescriptorSets = " << value.maxDescriptorSets << '\n';
+	s << "\tmaxPerStageDescriptorSamplers = " << value.maxPerStageDescriptorSamplers << '\n';
+	s << "\tmaxPerStageDescriptorUniformBuffers = " << value.maxPerStageDescriptorUniformBuffers << '\n';
+	s << "\tmaxPerStageDescriptorStorageBuffers = " << value.maxPerStageDescriptorStorageBuffers << '\n';
+	s << "\tmaxPerStageDescriptorSampledImages = " << value.maxPerStageDescriptorSampledImages << '\n';
+	s << "\tmaxPerStageDescriptorStorageImages = " << value.maxPerStageDescriptorStorageImages << '\n';
+	s << "\tmaxDescriptorSetSamplers = " << value.maxDescriptorSetSamplers << '\n';
+	s << "\tmaxDescriptorSetUniformBuffers = " << value.maxDescriptorSetUniformBuffers << '\n';
+	s << "\tmaxDescriptorSetUniformBuffersDynamic = " << value.maxDescriptorSetUniformBuffersDynamic << '\n';
+	s << "\tmaxDescriptorSetStorageBuffers = " << value.maxDescriptorSetStorageBuffers << '\n';
+	s << "\tmaxDescriptorSetStorageBuffersDynamic = " << value.maxDescriptorSetStorageBuffersDynamic << '\n';
+	s << "\tmaxDescriptorSetSampledImages = " << value.maxDescriptorSetSampledImages << '\n';
+	s << "\tmaxDescriptorSetStorageImages = " << value.maxDescriptorSetStorageImages << '\n';
+	s << "\tmaxVertexInputAttributes = " << value.maxVertexInputAttributes << '\n';
+	s << "\tmaxVertexInputBindings = " << value.maxVertexInputBindings << '\n';
+	s << "\tmaxVertexInputAttributeOffset = " << value.maxVertexInputAttributeOffset << '\n';
+	s << "\tmaxVertexInputBindingStride = " << value.maxVertexInputBindingStride << '\n';
+	s << "\tmaxVertexOutputComponents = " << value.maxVertexOutputComponents << '\n';
+	s << "\tmaxTessGenLevel = " << value.maxTessGenLevel << '\n';
+	s << "\tmaxTessPatchSize = " << value.maxTessPatchSize << '\n';
+	s << "\tmaxTessControlPerVertexInputComponents = " << value.maxTessControlPerVertexInputComponents << '\n';
+	s << "\tmaxTessControlPerVertexOutputComponents = " << value.maxTessControlPerVertexOutputComponents << '\n';
+	s << "\tmaxTessControlPerPatchOutputComponents = " << value.maxTessControlPerPatchOutputComponents << '\n';
+	s << "\tmaxTessControlTotalOutputComponents = " << value.maxTessControlTotalOutputComponents << '\n';
+	s << "\tmaxTessEvaluationInputComponents = " << value.maxTessEvaluationInputComponents << '\n';
+	s << "\tmaxTessEvaluationOutputComponents = " << value.maxTessEvaluationOutputComponents << '\n';
+	s << "\tmaxGeometryShaderInvocations = " << value.maxGeometryShaderInvocations << '\n';
+	s << "\tmaxGeometryInputComponents = " << value.maxGeometryInputComponents << '\n';
+	s << "\tmaxGeometryOutputComponents = " << value.maxGeometryOutputComponents << '\n';
+	s << "\tmaxGeometryOutputVertices = " << value.maxGeometryOutputVertices << '\n';
+	s << "\tmaxGeometryTotalOutputComponents = " << value.maxGeometryTotalOutputComponents << '\n';
+	s << "\tmaxFragmentInputComponents = " << value.maxFragmentInputComponents << '\n';
+	s << "\tmaxFragmentOutputBuffers = " << value.maxFragmentOutputBuffers << '\n';
+	s << "\tmaxFragmentDualSourceBuffers = " << value.maxFragmentDualSourceBuffers << '\n';
+	s << "\tmaxFragmentCombinedOutputResources = " << value.maxFragmentCombinedOutputResources << '\n';
+	s << "\tmaxComputeSharedMemorySize = " << value.maxComputeSharedMemorySize << '\n';
+	s << "\tmaxComputeWorkGroupCount = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.maxComputeWorkGroupCount), DE_ARRAY_END(value.maxComputeWorkGroupCount)) << '\n';
+	s << "\tmaxComputeWorkGroupInvocations = " << value.maxComputeWorkGroupInvocations << '\n';
+	s << "\tmaxComputeWorkGroupSize = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.maxComputeWorkGroupSize), DE_ARRAY_END(value.maxComputeWorkGroupSize)) << '\n';
+	s << "\tsubPixelPrecisionBits = " << value.subPixelPrecisionBits << '\n';
+	s << "\tsubTexelPrecisionBits = " << value.subTexelPrecisionBits << '\n';
+	s << "\tmipmapPrecisionBits = " << value.mipmapPrecisionBits << '\n';
+	s << "\tmaxDrawIndexedIndexValue = " << value.maxDrawIndexedIndexValue << '\n';
+	s << "\tmaxDrawIndirectInstanceCount = " << value.maxDrawIndirectInstanceCount << '\n';
+	s << "\tprimitiveRestartForPatches = " << value.primitiveRestartForPatches << '\n';
+	s << "\tmaxSamplerLodBias = " << value.maxSamplerLodBias << '\n';
+	s << "\tmaxSamplerAnisotropy = " << value.maxSamplerAnisotropy << '\n';
+	s << "\tmaxViewports = " << value.maxViewports << '\n';
+	s << "\tmaxViewportDimensions = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.maxViewportDimensions), DE_ARRAY_END(value.maxViewportDimensions)) << '\n';
+	s << "\tviewportBoundsRange = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.viewportBoundsRange), DE_ARRAY_END(value.viewportBoundsRange)) << '\n';
+	s << "\tviewportSubPixelBits = " << value.viewportSubPixelBits << '\n';
+	s << "\tminMemoryMapAlignment = " << value.minMemoryMapAlignment << '\n';
+	s << "\tminTexelBufferOffsetAlignment = " << value.minTexelBufferOffsetAlignment << '\n';
+	s << "\tminUniformBufferOffsetAlignment = " << value.minUniformBufferOffsetAlignment << '\n';
+	s << "\tminStorageBufferOffsetAlignment = " << value.minStorageBufferOffsetAlignment << '\n';
+	s << "\tminTexelOffset = " << value.minTexelOffset << '\n';
+	s << "\tmaxTexelOffset = " << value.maxTexelOffset << '\n';
+	s << "\tminTexelGatherOffset = " << value.minTexelGatherOffset << '\n';
+	s << "\tmaxTexelGatherOffset = " << value.maxTexelGatherOffset << '\n';
+	s << "\tminInterpolationOffset = " << value.minInterpolationOffset << '\n';
+	s << "\tmaxInterpolationOffset = " << value.maxInterpolationOffset << '\n';
+	s << "\tsubPixelInterpolationOffsetBits = " << value.subPixelInterpolationOffsetBits << '\n';
+	s << "\tmaxFramebufferWidth = " << value.maxFramebufferWidth << '\n';
+	s << "\tmaxFramebufferHeight = " << value.maxFramebufferHeight << '\n';
+	s << "\tmaxFramebufferLayers = " << value.maxFramebufferLayers << '\n';
+	s << "\tmaxFramebufferColorSamples = " << value.maxFramebufferColorSamples << '\n';
+	s << "\tmaxFramebufferDepthSamples = " << value.maxFramebufferDepthSamples << '\n';
+	s << "\tmaxFramebufferStencilSamples = " << value.maxFramebufferStencilSamples << '\n';
+	s << "\tmaxColorAttachments = " << value.maxColorAttachments << '\n';
+	s << "\tmaxSampledImageColorSamples = " << value.maxSampledImageColorSamples << '\n';
+	s << "\tmaxSampledImageDepthSamples = " << value.maxSampledImageDepthSamples << '\n';
+	s << "\tmaxSampledImageIntegerSamples = " << value.maxSampledImageIntegerSamples << '\n';
+	s << "\tmaxStorageImageSamples = " << value.maxStorageImageSamples << '\n';
+	s << "\tmaxSampleMaskWords = " << value.maxSampleMaskWords << '\n';
+	s << "\ttimestampFrequency = " << value.timestampFrequency << '\n';
+	s << "\tmaxClipDistances = " << value.maxClipDistances << '\n';
+	s << "\tmaxCullDistances = " << value.maxCullDistances << '\n';
+	s << "\tmaxCombinedClipAndCullDistances = " << value.maxCombinedClipAndCullDistances << '\n';
+	s << "\tpointSizeRange = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.pointSizeRange), DE_ARRAY_END(value.pointSizeRange)) << '\n';
+	s << "\tlineWidthRange = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.lineWidthRange), DE_ARRAY_END(value.lineWidthRange)) << '\n';
+	s << "\tpointSizeGranularity = " << value.pointSizeGranularity << '\n';
+	s << "\tlineWidthGranularity = " << value.lineWidthGranularity << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDeviceSparseProperties& value)
+{
+	s << "VkPhysicalDeviceSparseProperties = {\n";
+	s << "\tresidencyStandard2DBlockShape = " << value.residencyStandard2DBlockShape << '\n';
+	s << "\tresidencyStandard2DMSBlockShape = " << value.residencyStandard2DMSBlockShape << '\n';
+	s << "\tresidencyStandard3DBlockShape = " << value.residencyStandard3DBlockShape << '\n';
+	s << "\tresidencyAlignedMipSize = " << value.residencyAlignedMipSize << '\n';
+	s << "\tresidencyNonResident = " << value.residencyNonResident << '\n';
+	s << "\tresidencyNonResidentStrict = " << value.residencyNonResidentStrict << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDeviceProperties& value)
+{
+	s << "VkPhysicalDeviceProperties = {\n";
+	s << "\tapiVersion = " << value.apiVersion << '\n';
+	s << "\tdriverVersion = " << value.driverVersion << '\n';
+	s << "\tvendorId = " << value.vendorId << '\n';
+	s << "\tdeviceId = " << value.deviceId << '\n';
+	s << "\tdeviceType = " << value.deviceType << '\n';
+	s << "\tdeviceName = " << (const char*)value.deviceName << '\n';
+	s << "\tpipelineCacheUUID = " << '\n' << tcu::formatArray(tcu::Format::HexIterator<deUint8>(DE_ARRAY_BEGIN(value.pipelineCacheUUID)), tcu::Format::HexIterator<deUint8>(DE_ARRAY_END(value.pipelineCacheUUID))) << '\n';
+	s << "\tlimits = " << value.limits << '\n';
+	s << "\tsparseProperties = " << value.sparseProperties << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkQueueFamilyProperties& value)
+{
+	s << "VkQueueFamilyProperties = {\n";
+	s << "\tqueueFlags = " << getQueueFlagsStr(value.queueFlags) << '\n';
+	s << "\tqueueCount = " << value.queueCount << '\n';
+	s << "\tsupportsTimestamps = " << value.supportsTimestamps << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMemoryType& value)
+{
+	s << "VkMemoryType = {\n";
+	s << "\tpropertyFlags = " << getMemoryPropertyFlagsStr(value.propertyFlags) << '\n';
+	s << "\theapIndex = " << value.heapIndex << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMemoryHeap& value)
+{
+	s << "VkMemoryHeap = {\n";
+	s << "\tsize = " << value.size << '\n';
+	s << "\tflags = " << getMemoryHeapFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPhysicalDeviceMemoryProperties& value)
+{
+	s << "VkPhysicalDeviceMemoryProperties = {\n";
+	s << "\tmemoryTypeCount = " << value.memoryTypeCount << '\n';
+	s << "\tmemoryTypes = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.memoryTypes), DE_ARRAY_END(value.memoryTypes)) << '\n';
+	s << "\tmemoryHeapCount = " << value.memoryHeapCount << '\n';
+	s << "\tmemoryHeaps = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.memoryHeaps), DE_ARRAY_END(value.memoryHeaps)) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDeviceQueueCreateInfo& value)
+{
+	s << "VkDeviceQueueCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tqueueFamilyIndex = " << value.queueFamilyIndex << '\n';
+	s << "\tqueueCount = " << value.queueCount << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDeviceCreateInfo& value)
+{
+	s << "VkDeviceCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tqueueRecordCount = " << value.queueRecordCount << '\n';
+	s << "\tpRequestedQueues = " << value.pRequestedQueues << '\n';
+	s << "\tlayerCount = " << value.layerCount << '\n';
+	s << "\tppEnabledLayerNames = " << value.ppEnabledLayerNames << '\n';
+	s << "\textensionCount = " << value.extensionCount << '\n';
+	s << "\tppEnabledExtensionNames = " << value.ppEnabledExtensionNames << '\n';
+	s << "\tpEnabledFeatures = " << value.pEnabledFeatures << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkExtensionProperties& value)
+{
+	s << "VkExtensionProperties = {\n";
+	s << "\textName = " << (const char*)value.extName << '\n';
+	s << "\tspecVersion = " << value.specVersion << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkLayerProperties& value)
+{
+	s << "VkLayerProperties = {\n";
+	s << "\tlayerName = " << (const char*)value.layerName << '\n';
+	s << "\tspecVersion = " << value.specVersion << '\n';
+	s << "\timplVersion = " << value.implVersion << '\n';
+	s << "\tdescription = " << (const char*)value.description << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMemoryAllocInfo& value)
+{
+	s << "VkMemoryAllocInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tallocationSize = " << value.allocationSize << '\n';
+	s << "\tmemoryTypeIndex = " << value.memoryTypeIndex << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMappedMemoryRange& value)
+{
+	s << "VkMappedMemoryRange = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tmem = " << value.mem << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << "\tsize = " << value.size << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMemoryRequirements& value)
+{
+	s << "VkMemoryRequirements = {\n";
+	s << "\tsize = " << value.size << '\n';
+	s << "\talignment = " << value.alignment << '\n';
+	s << "\tmemoryTypeBits = " << value.memoryTypeBits << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSparseImageFormatProperties& value)
+{
+	s << "VkSparseImageFormatProperties = {\n";
+	s << "\taspect = " << value.aspect << '\n';
+	s << "\timageGranularity = " << value.imageGranularity << '\n';
+	s << "\tflags = " << getSparseImageFormatFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSparseImageMemoryRequirements& value)
+{
+	s << "VkSparseImageMemoryRequirements = {\n";
+	s << "\tformatProps = " << value.formatProps << '\n';
+	s << "\timageMipTailStartLOD = " << value.imageMipTailStartLOD << '\n';
+	s << "\timageMipTailSize = " << value.imageMipTailSize << '\n';
+	s << "\timageMipTailOffset = " << value.imageMipTailOffset << '\n';
+	s << "\timageMipTailStride = " << value.imageMipTailStride << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSparseMemoryBindInfo& value)
+{
+	s << "VkSparseMemoryBindInfo = {\n";
+	s << "\trangeOffset = " << value.rangeOffset << '\n';
+	s << "\trangeSize = " << value.rangeSize << '\n';
+	s << "\tmemOffset = " << value.memOffset << '\n';
+	s << "\tmem = " << value.mem << '\n';
+	s << "\tflags = " << getSparseMemoryBindFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageSubresource& value)
+{
+	s << "VkImageSubresource = {\n";
+	s << "\taspect = " << value.aspect << '\n';
+	s << "\tmipLevel = " << value.mipLevel << '\n';
+	s << "\tarrayLayer = " << value.arrayLayer << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkOffset3D& value)
+{
+	s << "VkOffset3D = {\n";
+	s << "\tx = " << value.x << '\n';
+	s << "\ty = " << value.y << '\n';
+	s << "\tz = " << value.z << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSparseImageMemoryBindInfo& value)
+{
+	s << "VkSparseImageMemoryBindInfo = {\n";
+	s << "\tsubresource = " << value.subresource << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << "\tmemOffset = " << value.memOffset << '\n';
+	s << "\tmem = " << value.mem << '\n';
+	s << "\tflags = " << getSparseMemoryBindFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkFenceCreateInfo& value)
+{
+	s << "VkFenceCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tflags = " << getFenceCreateFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSemaphoreCreateInfo& value)
+{
+	s << "VkSemaphoreCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tflags = " << value.flags << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkEventCreateInfo& value)
+{
+	s << "VkEventCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tflags = " << value.flags << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkQueryPoolCreateInfo& value)
+{
+	s << "VkQueryPoolCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tqueryType = " << value.queryType << '\n';
+	s << "\tslots = " << value.slots << '\n';
+	s << "\tpipelineStatistics = " << getQueryPipelineStatisticFlagsStr(value.pipelineStatistics) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkBufferCreateInfo& value)
+{
+	s << "VkBufferCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tsize = " << value.size << '\n';
+	s << "\tusage = " << getBufferUsageFlagsStr(value.usage) << '\n';
+	s << "\tflags = " << getBufferCreateFlagsStr(value.flags) << '\n';
+	s << "\tsharingMode = " << value.sharingMode << '\n';
+	s << "\tqueueFamilyCount = " << value.queueFamilyCount << '\n';
+	s << "\tpQueueFamilyIndices = " << value.pQueueFamilyIndices << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkBufferViewCreateInfo& value)
+{
+	s << "VkBufferViewCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tbuffer = " << value.buffer << '\n';
+	s << "\tformat = " << value.format << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << "\trange = " << value.range << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageCreateInfo& value)
+{
+	s << "VkImageCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\timageType = " << value.imageType << '\n';
+	s << "\tformat = " << value.format << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << "\tmipLevels = " << value.mipLevels << '\n';
+	s << "\tarraySize = " << value.arraySize << '\n';
+	s << "\tsamples = " << value.samples << '\n';
+	s << "\ttiling = " << value.tiling << '\n';
+	s << "\tusage = " << getImageUsageFlagsStr(value.usage) << '\n';
+	s << "\tflags = " << getImageCreateFlagsStr(value.flags) << '\n';
+	s << "\tsharingMode = " << value.sharingMode << '\n';
+	s << "\tqueueFamilyCount = " << value.queueFamilyCount << '\n';
+	s << "\tpQueueFamilyIndices = " << value.pQueueFamilyIndices << '\n';
+	s << "\tinitialLayout = " << value.initialLayout << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSubresourceLayout& value)
+{
+	s << "VkSubresourceLayout = {\n";
+	s << "\toffset = " << value.offset << '\n';
+	s << "\tsize = " << value.size << '\n';
+	s << "\trowPitch = " << value.rowPitch << '\n';
+	s << "\tdepthPitch = " << value.depthPitch << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkChannelMapping& value)
+{
+	s << "VkChannelMapping = {\n";
+	s << "\tr = " << value.r << '\n';
+	s << "\tg = " << value.g << '\n';
+	s << "\tb = " << value.b << '\n';
+	s << "\ta = " << value.a << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageSubresourceRange& value)
+{
+	s << "VkImageSubresourceRange = {\n";
+	s << "\taspectMask = " << getImageAspectFlagsStr(value.aspectMask) << '\n';
+	s << "\tbaseMipLevel = " << value.baseMipLevel << '\n';
+	s << "\tmipLevels = " << value.mipLevels << '\n';
+	s << "\tbaseArrayLayer = " << value.baseArrayLayer << '\n';
+	s << "\tarraySize = " << value.arraySize << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageViewCreateInfo& value)
+{
+	s << "VkImageViewCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\timage = " << value.image << '\n';
+	s << "\tviewType = " << value.viewType << '\n';
+	s << "\tformat = " << value.format << '\n';
+	s << "\tchannels = " << value.channels << '\n';
+	s << "\tsubresourceRange = " << value.subresourceRange << '\n';
+	s << "\tflags = " << getImageViewCreateFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkShaderModuleCreateInfo& value)
+{
+	s << "VkShaderModuleCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tcodeSize = " << value.codeSize << '\n';
+	s << "\tpCode = " << value.pCode << '\n';
+	s << "\tflags = " << value.flags << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkShaderCreateInfo& value)
+{
+	s << "VkShaderCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tmodule = " << value.module << '\n';
+	s << "\tpName = " << getCharPtrStr(value.pName) << '\n';
+	s << "\tflags = " << value.flags << '\n';
+	s << "\tstage = " << value.stage << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineCacheCreateInfo& value)
+{
+	s << "VkPipelineCacheCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tinitialSize = " << value.initialSize << '\n';
+	s << "\tinitialData = " << value.initialData << '\n';
+	s << "\tmaxSize = " << value.maxSize << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSpecializationMapEntry& value)
+{
+	s << "VkSpecializationMapEntry = {\n";
+	s << "\tconstantId = " << value.constantId << '\n';
+	s << "\tsize = " << value.size << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSpecializationInfo& value)
+{
+	s << "VkSpecializationInfo = {\n";
+	s << "\tmapEntryCount = " << value.mapEntryCount << '\n';
+	s << "\tpMap = " << value.pMap << '\n';
+	s << "\tdataSize = " << value.dataSize << '\n';
+	s << "\tpData = " << value.pData << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineShaderStageCreateInfo& value)
+{
+	s << "VkPipelineShaderStageCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tstage = " << value.stage << '\n';
+	s << "\tshader = " << value.shader << '\n';
+	s << "\tpSpecializationInfo = " << value.pSpecializationInfo << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkVertexInputBindingDescription& value)
+{
+	s << "VkVertexInputBindingDescription = {\n";
+	s << "\tbinding = " << value.binding << '\n';
+	s << "\tstrideInBytes = " << value.strideInBytes << '\n';
+	s << "\tstepRate = " << value.stepRate << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkVertexInputAttributeDescription& value)
+{
+	s << "VkVertexInputAttributeDescription = {\n";
+	s << "\tlocation = " << value.location << '\n';
+	s << "\tbinding = " << value.binding << '\n';
+	s << "\tformat = " << value.format << '\n';
+	s << "\toffsetInBytes = " << value.offsetInBytes << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineVertexInputStateCreateInfo& value)
+{
+	s << "VkPipelineVertexInputStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tbindingCount = " << value.bindingCount << '\n';
+	s << "\tpVertexBindingDescriptions = " << value.pVertexBindingDescriptions << '\n';
+	s << "\tattributeCount = " << value.attributeCount << '\n';
+	s << "\tpVertexAttributeDescriptions = " << value.pVertexAttributeDescriptions << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineInputAssemblyStateCreateInfo& value)
+{
+	s << "VkPipelineInputAssemblyStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\ttopology = " << value.topology << '\n';
+	s << "\tprimitiveRestartEnable = " << value.primitiveRestartEnable << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineTessellationStateCreateInfo& value)
+{
+	s << "VkPipelineTessellationStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tpatchControlPoints = " << value.patchControlPoints << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkViewport& value)
+{
+	s << "VkViewport = {\n";
+	s << "\toriginX = " << value.originX << '\n';
+	s << "\toriginY = " << value.originY << '\n';
+	s << "\twidth = " << value.width << '\n';
+	s << "\theight = " << value.height << '\n';
+	s << "\tminDepth = " << value.minDepth << '\n';
+	s << "\tmaxDepth = " << value.maxDepth << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkOffset2D& value)
+{
+	s << "VkOffset2D = {\n";
+	s << "\tx = " << value.x << '\n';
+	s << "\ty = " << value.y << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkExtent2D& value)
+{
+	s << "VkExtent2D = {\n";
+	s << "\twidth = " << value.width << '\n';
+	s << "\theight = " << value.height << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkRect2D& value)
+{
+	s << "VkRect2D = {\n";
+	s << "\toffset = " << value.offset << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineViewportStateCreateInfo& value)
+{
+	s << "VkPipelineViewportStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tviewportCount = " << value.viewportCount << '\n';
+	s << "\tpViewports = " << value.pViewports << '\n';
+	s << "\tscissorCount = " << value.scissorCount << '\n';
+	s << "\tpScissors = " << value.pScissors << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineRasterStateCreateInfo& value)
+{
+	s << "VkPipelineRasterStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tdepthClipEnable = " << value.depthClipEnable << '\n';
+	s << "\trasterizerDiscardEnable = " << value.rasterizerDiscardEnable << '\n';
+	s << "\tfillMode = " << value.fillMode << '\n';
+	s << "\tcullMode = " << value.cullMode << '\n';
+	s << "\tfrontFace = " << value.frontFace << '\n';
+	s << "\tdepthBiasEnable = " << value.depthBiasEnable << '\n';
+	s << "\tdepthBias = " << value.depthBias << '\n';
+	s << "\tdepthBiasClamp = " << value.depthBiasClamp << '\n';
+	s << "\tslopeScaledDepthBias = " << value.slopeScaledDepthBias << '\n';
+	s << "\tlineWidth = " << value.lineWidth << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineMultisampleStateCreateInfo& value)
+{
+	s << "VkPipelineMultisampleStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\trasterSamples = " << value.rasterSamples << '\n';
+	s << "\tsampleShadingEnable = " << value.sampleShadingEnable << '\n';
+	s << "\tminSampleShading = " << value.minSampleShading << '\n';
+	s << "\tpSampleMask = " << value.pSampleMask << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkStencilOpState& value)
+{
+	s << "VkStencilOpState = {\n";
+	s << "\tstencilFailOp = " << value.stencilFailOp << '\n';
+	s << "\tstencilPassOp = " << value.stencilPassOp << '\n';
+	s << "\tstencilDepthFailOp = " << value.stencilDepthFailOp << '\n';
+	s << "\tstencilCompareOp = " << value.stencilCompareOp << '\n';
+	s << "\tstencilCompareMask = " << value.stencilCompareMask << '\n';
+	s << "\tstencilWriteMask = " << value.stencilWriteMask << '\n';
+	s << "\tstencilReference = " << value.stencilReference << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineDepthStencilStateCreateInfo& value)
+{
+	s << "VkPipelineDepthStencilStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tdepthTestEnable = " << value.depthTestEnable << '\n';
+	s << "\tdepthWriteEnable = " << value.depthWriteEnable << '\n';
+	s << "\tdepthCompareOp = " << value.depthCompareOp << '\n';
+	s << "\tdepthBoundsTestEnable = " << value.depthBoundsTestEnable << '\n';
+	s << "\tstencilTestEnable = " << value.stencilTestEnable << '\n';
+	s << "\tfront = " << value.front << '\n';
+	s << "\tback = " << value.back << '\n';
+	s << "\tminDepthBounds = " << value.minDepthBounds << '\n';
+	s << "\tmaxDepthBounds = " << value.maxDepthBounds << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineColorBlendAttachmentState& value)
+{
+	s << "VkPipelineColorBlendAttachmentState = {\n";
+	s << "\tblendEnable = " << value.blendEnable << '\n';
+	s << "\tsrcBlendColor = " << value.srcBlendColor << '\n';
+	s << "\tdestBlendColor = " << value.destBlendColor << '\n';
+	s << "\tblendOpColor = " << value.blendOpColor << '\n';
+	s << "\tsrcBlendAlpha = " << value.srcBlendAlpha << '\n';
+	s << "\tdestBlendAlpha = " << value.destBlendAlpha << '\n';
+	s << "\tblendOpAlpha = " << value.blendOpAlpha << '\n';
+	s << "\tchannelWriteMask = " << getChannelFlagsStr(value.channelWriteMask) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineColorBlendStateCreateInfo& value)
+{
+	s << "VkPipelineColorBlendStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\talphaToCoverageEnable = " << value.alphaToCoverageEnable << '\n';
+	s << "\talphaToOneEnable = " << value.alphaToOneEnable << '\n';
+	s << "\tlogicOpEnable = " << value.logicOpEnable << '\n';
+	s << "\tlogicOp = " << value.logicOp << '\n';
+	s << "\tattachmentCount = " << value.attachmentCount << '\n';
+	s << "\tpAttachments = " << value.pAttachments << '\n';
+	s << "\tblendConst = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.blendConst), DE_ARRAY_END(value.blendConst)) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineDynamicStateCreateInfo& value)
+{
+	s << "VkPipelineDynamicStateCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tdynamicStateCount = " << value.dynamicStateCount << '\n';
+	s << "\tpDynamicStates = " << value.pDynamicStates << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkGraphicsPipelineCreateInfo& value)
+{
+	s << "VkGraphicsPipelineCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tstageCount = " << value.stageCount << '\n';
+	s << "\tpStages = " << value.pStages << '\n';
+	s << "\tpVertexInputState = " << value.pVertexInputState << '\n';
+	s << "\tpInputAssemblyState = " << value.pInputAssemblyState << '\n';
+	s << "\tpTessellationState = " << value.pTessellationState << '\n';
+	s << "\tpViewportState = " << value.pViewportState << '\n';
+	s << "\tpRasterState = " << value.pRasterState << '\n';
+	s << "\tpMultisampleState = " << value.pMultisampleState << '\n';
+	s << "\tpDepthStencilState = " << value.pDepthStencilState << '\n';
+	s << "\tpColorBlendState = " << value.pColorBlendState << '\n';
+	s << "\tpDynamicState = " << value.pDynamicState << '\n';
+	s << "\tflags = " << getPipelineCreateFlagsStr(value.flags) << '\n';
+	s << "\tlayout = " << value.layout << '\n';
+	s << "\trenderPass = " << value.renderPass << '\n';
+	s << "\tsubpass = " << value.subpass << '\n';
+	s << "\tbasePipelineHandle = " << value.basePipelineHandle << '\n';
+	s << "\tbasePipelineIndex = " << value.basePipelineIndex << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkComputePipelineCreateInfo& value)
+{
+	s << "VkComputePipelineCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tstage = " << value.stage << '\n';
+	s << "\tflags = " << getPipelineCreateFlagsStr(value.flags) << '\n';
+	s << "\tlayout = " << value.layout << '\n';
+	s << "\tbasePipelineHandle = " << value.basePipelineHandle << '\n';
+	s << "\tbasePipelineIndex = " << value.basePipelineIndex << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPushConstantRange& value)
+{
+	s << "VkPushConstantRange = {\n";
+	s << "\tstageFlags = " << getShaderStageFlagsStr(value.stageFlags) << '\n';
+	s << "\tstart = " << value.start << '\n';
+	s << "\tlength = " << value.length << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkPipelineLayoutCreateInfo& value)
+{
+	s << "VkPipelineLayoutCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tdescriptorSetCount = " << value.descriptorSetCount << '\n';
+	s << "\tpSetLayouts = " << value.pSetLayouts << '\n';
+	s << "\tpushConstantRangeCount = " << value.pushConstantRangeCount << '\n';
+	s << "\tpPushConstantRanges = " << value.pPushConstantRanges << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSamplerCreateInfo& value)
+{
+	s << "VkSamplerCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tmagFilter = " << value.magFilter << '\n';
+	s << "\tminFilter = " << value.minFilter << '\n';
+	s << "\tmipMode = " << value.mipMode << '\n';
+	s << "\taddressModeU = " << value.addressModeU << '\n';
+	s << "\taddressModeV = " << value.addressModeV << '\n';
+	s << "\taddressModeW = " << value.addressModeW << '\n';
+	s << "\tmipLodBias = " << value.mipLodBias << '\n';
+	s << "\tmaxAnisotropy = " << value.maxAnisotropy << '\n';
+	s << "\tcompareEnable = " << value.compareEnable << '\n';
+	s << "\tcompareOp = " << value.compareOp << '\n';
+	s << "\tminLod = " << value.minLod << '\n';
+	s << "\tmaxLod = " << value.maxLod << '\n';
+	s << "\tborderColor = " << value.borderColor << '\n';
+	s << "\tunnormalizedCoordinates = " << value.unnormalizedCoordinates << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorSetLayoutBinding& value)
+{
+	s << "VkDescriptorSetLayoutBinding = {\n";
+	s << "\tdescriptorType = " << value.descriptorType << '\n';
+	s << "\tarraySize = " << value.arraySize << '\n';
+	s << "\tstageFlags = " << getShaderStageFlagsStr(value.stageFlags) << '\n';
+	s << "\tpImmutableSamplers = " << value.pImmutableSamplers << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorSetLayoutCreateInfo& value)
+{
+	s << "VkDescriptorSetLayoutCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tcount = " << value.count << '\n';
+	s << "\tpBinding = " << value.pBinding << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorTypeCount& value)
+{
+	s << "VkDescriptorTypeCount = {\n";
+	s << "\ttype = " << value.type << '\n';
+	s << "\tcount = " << value.count << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorPoolCreateInfo& value)
+{
+	s << "VkDescriptorPoolCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tpoolUsage = " << value.poolUsage << '\n';
+	s << "\tmaxSets = " << value.maxSets << '\n';
+	s << "\tcount = " << value.count << '\n';
+	s << "\tpTypeCount = " << value.pTypeCount << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorBufferInfo& value)
+{
+	s << "VkDescriptorBufferInfo = {\n";
+	s << "\tbuffer = " << value.buffer << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << "\trange = " << value.range << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDescriptorInfo& value)
+{
+	s << "VkDescriptorInfo = {\n";
+	s << "\tbufferView = " << value.bufferView << '\n';
+	s << "\tsampler = " << value.sampler << '\n';
+	s << "\timageView = " << value.imageView << '\n';
+	s << "\timageLayout = " << value.imageLayout << '\n';
+	s << "\tbufferInfo = " << value.bufferInfo << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkWriteDescriptorSet& value)
+{
+	s << "VkWriteDescriptorSet = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tdestSet = " << value.destSet << '\n';
+	s << "\tdestBinding = " << value.destBinding << '\n';
+	s << "\tdestArrayElement = " << value.destArrayElement << '\n';
+	s << "\tcount = " << value.count << '\n';
+	s << "\tdescriptorType = " << value.descriptorType << '\n';
+	s << "\tpDescriptors = " << value.pDescriptors << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkCopyDescriptorSet& value)
+{
+	s << "VkCopyDescriptorSet = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tsrcSet = " << value.srcSet << '\n';
+	s << "\tsrcBinding = " << value.srcBinding << '\n';
+	s << "\tsrcArrayElement = " << value.srcArrayElement << '\n';
+	s << "\tdestSet = " << value.destSet << '\n';
+	s << "\tdestBinding = " << value.destBinding << '\n';
+	s << "\tdestArrayElement = " << value.destArrayElement << '\n';
+	s << "\tcount = " << value.count << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkFramebufferCreateInfo& value)
+{
+	s << "VkFramebufferCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\trenderPass = " << value.renderPass << '\n';
+	s << "\tattachmentCount = " << value.attachmentCount << '\n';
+	s << "\tpAttachments = " << value.pAttachments << '\n';
+	s << "\twidth = " << value.width << '\n';
+	s << "\theight = " << value.height << '\n';
+	s << "\tlayers = " << value.layers << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkAttachmentDescription& value)
+{
+	s << "VkAttachmentDescription = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tformat = " << value.format << '\n';
+	s << "\tsamples = " << value.samples << '\n';
+	s << "\tloadOp = " << value.loadOp << '\n';
+	s << "\tstoreOp = " << value.storeOp << '\n';
+	s << "\tstencilLoadOp = " << value.stencilLoadOp << '\n';
+	s << "\tstencilStoreOp = " << value.stencilStoreOp << '\n';
+	s << "\tinitialLayout = " << value.initialLayout << '\n';
+	s << "\tfinalLayout = " << value.finalLayout << '\n';
+	s << "\tflags = " << getAttachmentDescriptionFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkAttachmentReference& value)
+{
+	s << "VkAttachmentReference = {\n";
+	s << "\tattachment = " << value.attachment << '\n';
+	s << "\tlayout = " << value.layout << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSubpassDescription& value)
+{
+	s << "VkSubpassDescription = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tpipelineBindPoint = " << value.pipelineBindPoint << '\n';
+	s << "\tflags = " << getSubpassDescriptionFlagsStr(value.flags) << '\n';
+	s << "\tinputCount = " << value.inputCount << '\n';
+	s << "\tpInputAttachments = " << value.pInputAttachments << '\n';
+	s << "\tcolorCount = " << value.colorCount << '\n';
+	s << "\tpColorAttachments = " << value.pColorAttachments << '\n';
+	s << "\tpResolveAttachments = " << value.pResolveAttachments << '\n';
+	s << "\tdepthStencilAttachment = " << value.depthStencilAttachment << '\n';
+	s << "\tpreserveCount = " << value.preserveCount << '\n';
+	s << "\tpPreserveAttachments = " << value.pPreserveAttachments << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkSubpassDependency& value)
+{
+	s << "VkSubpassDependency = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tsrcSubpass = " << value.srcSubpass << '\n';
+	s << "\tdestSubpass = " << value.destSubpass << '\n';
+	s << "\tsrcStageMask = " << getPipelineStageFlagsStr(value.srcStageMask) << '\n';
+	s << "\tdestStageMask = " << getPipelineStageFlagsStr(value.destStageMask) << '\n';
+	s << "\toutputMask = " << getMemoryOutputFlagsStr(value.outputMask) << '\n';
+	s << "\tinputMask = " << getMemoryInputFlagsStr(value.inputMask) << '\n';
+	s << "\tbyRegion = " << value.byRegion << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkRenderPassCreateInfo& value)
+{
+	s << "VkRenderPassCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tattachmentCount = " << value.attachmentCount << '\n';
+	s << "\tpAttachments = " << value.pAttachments << '\n';
+	s << "\tsubpassCount = " << value.subpassCount << '\n';
+	s << "\tpSubpasses = " << value.pSubpasses << '\n';
+	s << "\tdependencyCount = " << value.dependencyCount << '\n';
+	s << "\tpDependencies = " << value.pDependencies << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkCmdPoolCreateInfo& value)
+{
+	s << "VkCmdPoolCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tqueueFamilyIndex = " << value.queueFamilyIndex << '\n';
+	s << "\tflags = " << getCmdPoolCreateFlagsStr(value.flags) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkCmdBufferCreateInfo& value)
+{
+	s << "VkCmdBufferCreateInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tcmdPool = " << value.cmdPool << '\n';
+	s << "\tlevel = " << value.level << '\n';
+	s << "\tflags = " << value.flags << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkCmdBufferBeginInfo& value)
+{
+	s << "VkCmdBufferBeginInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\tflags = " << getCmdBufferOptimizeFlagsStr(value.flags) << '\n';
+	s << "\trenderPass = " << value.renderPass << '\n';
+	s << "\tsubpass = " << value.subpass << '\n';
+	s << "\tframebuffer = " << value.framebuffer << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkBufferCopy& value)
+{
+	s << "VkBufferCopy = {\n";
+	s << "\tsrcOffset = " << value.srcOffset << '\n';
+	s << "\tdestOffset = " << value.destOffset << '\n';
+	s << "\tcopySize = " << value.copySize << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageSubresourceCopy& value)
+{
+	s << "VkImageSubresourceCopy = {\n";
+	s << "\taspect = " << value.aspect << '\n';
+	s << "\tmipLevel = " << value.mipLevel << '\n';
+	s << "\tarrayLayer = " << value.arrayLayer << '\n';
+	s << "\tarraySize = " << value.arraySize << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageCopy& value)
+{
+	s << "VkImageCopy = {\n";
+	s << "\tsrcSubresource = " << value.srcSubresource << '\n';
+	s << "\tsrcOffset = " << value.srcOffset << '\n';
+	s << "\tdestSubresource = " << value.destSubresource << '\n';
+	s << "\tdestOffset = " << value.destOffset << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageBlit& value)
+{
+	s << "VkImageBlit = {\n";
+	s << "\tsrcSubresource = " << value.srcSubresource << '\n';
+	s << "\tsrcOffset = " << value.srcOffset << '\n';
+	s << "\tsrcExtent = " << value.srcExtent << '\n';
+	s << "\tdestSubresource = " << value.destSubresource << '\n';
+	s << "\tdestOffset = " << value.destOffset << '\n';
+	s << "\tdestExtent = " << value.destExtent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkBufferImageCopy& value)
+{
+	s << "VkBufferImageCopy = {\n";
+	s << "\tbufferOffset = " << value.bufferOffset << '\n';
+	s << "\tbufferRowLength = " << value.bufferRowLength << '\n';
+	s << "\tbufferImageHeight = " << value.bufferImageHeight << '\n';
+	s << "\timageSubresource = " << value.imageSubresource << '\n';
+	s << "\timageOffset = " << value.imageOffset << '\n';
+	s << "\timageExtent = " << value.imageExtent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkClearColorValue& value)
+{
+	s << "VkClearColorValue = {\n";
+	s << "\tfloat32 = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.float32), DE_ARRAY_END(value.float32)) << '\n';
+	s << "\tint32 = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.int32), DE_ARRAY_END(value.int32)) << '\n';
+	s << "\tuint32 = " << '\n' << tcu::formatArray(DE_ARRAY_BEGIN(value.uint32), DE_ARRAY_END(value.uint32)) << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkClearDepthStencilValue& value)
+{
+	s << "VkClearDepthStencilValue = {\n";
+	s << "\tdepth = " << value.depth << '\n';
+	s << "\tstencil = " << value.stencil << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkRect3D& value)
+{
+	s << "VkRect3D = {\n";
+	s << "\toffset = " << value.offset << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageResolve& value)
+{
+	s << "VkImageResolve = {\n";
+	s << "\tsrcSubresource = " << value.srcSubresource << '\n';
+	s << "\tsrcOffset = " << value.srcOffset << '\n';
+	s << "\tdestSubresource = " << value.destSubresource << '\n';
+	s << "\tdestOffset = " << value.destOffset << '\n';
+	s << "\textent = " << value.extent << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkClearValue& value)
+{
+	s << "VkClearValue = {\n";
+	s << "\tcolor = " << value.color << '\n';
+	s << "\tdepthStencil = " << value.depthStencil << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkRenderPassBeginInfo& value)
+{
+	s << "VkRenderPassBeginInfo = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\trenderPass = " << value.renderPass << '\n';
+	s << "\tframebuffer = " << value.framebuffer << '\n';
+	s << "\trenderArea = " << value.renderArea << '\n';
+	s << "\tclearValueCount = " << value.clearValueCount << '\n';
+	s << "\tpClearValues = " << value.pClearValues << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkBufferMemoryBarrier& value)
+{
+	s << "VkBufferMemoryBarrier = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\toutputMask = " << getMemoryOutputFlagsStr(value.outputMask) << '\n';
+	s << "\tinputMask = " << getMemoryInputFlagsStr(value.inputMask) << '\n';
+	s << "\tsrcQueueFamilyIndex = " << value.srcQueueFamilyIndex << '\n';
+	s << "\tdestQueueFamilyIndex = " << value.destQueueFamilyIndex << '\n';
+	s << "\tbuffer = " << value.buffer << '\n';
+	s << "\toffset = " << value.offset << '\n';
+	s << "\tsize = " << value.size << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDispatchIndirectCmd& value)
+{
+	s << "VkDispatchIndirectCmd = {\n";
+	s << "\tx = " << value.x << '\n';
+	s << "\ty = " << value.y << '\n';
+	s << "\tz = " << value.z << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDrawIndexedIndirectCmd& value)
+{
+	s << "VkDrawIndexedIndirectCmd = {\n";
+	s << "\tindexCount = " << value.indexCount << '\n';
+	s << "\tinstanceCount = " << value.instanceCount << '\n';
+	s << "\tfirstIndex = " << value.firstIndex << '\n';
+	s << "\tvertexOffset = " << value.vertexOffset << '\n';
+	s << "\tfirstInstance = " << value.firstInstance << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkDrawIndirectCmd& value)
+{
+	s << "VkDrawIndirectCmd = {\n";
+	s << "\tvertexCount = " << value.vertexCount << '\n';
+	s << "\tinstanceCount = " << value.instanceCount << '\n';
+	s << "\tfirstVertex = " << value.firstVertex << '\n';
+	s << "\tfirstInstance = " << value.firstInstance << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkImageMemoryBarrier& value)
+{
+	s << "VkImageMemoryBarrier = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\toutputMask = " << getMemoryOutputFlagsStr(value.outputMask) << '\n';
+	s << "\tinputMask = " << getMemoryInputFlagsStr(value.inputMask) << '\n';
+	s << "\toldLayout = " << value.oldLayout << '\n';
+	s << "\tnewLayout = " << value.newLayout << '\n';
+	s << "\tsrcQueueFamilyIndex = " << value.srcQueueFamilyIndex << '\n';
+	s << "\tdestQueueFamilyIndex = " << value.destQueueFamilyIndex << '\n';
+	s << "\timage = " << value.image << '\n';
+	s << "\tsubresourceRange = " << value.subresourceRange << '\n';
+	s << '}';
+	return s;
+}
+
+std::ostream& operator<< (std::ostream& s, const VkMemoryBarrier& value)
+{
+	s << "VkMemoryBarrier = {\n";
+	s << "\tsType = " << value.sType << '\n';
+	s << "\tpNext = " << value.pNext << '\n';
+	s << "\toutputMask = " << getMemoryOutputFlagsStr(value.outputMask) << '\n';
+	s << "\tinputMask = " << getMemoryInputFlagsStr(value.inputMask) << '\n';
+	s << '}';
+	return s;
+}
diff --git a/external/vulkancts/framework/vulkan/vkStructTypes.inl b/external/vulkancts/framework/vulkan/vkStructTypes.inl
new file mode 100644
index 0000000..eae7478
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkStructTypes.inl
@@ -0,0 +1,1085 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+struct VkApplicationInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	const char*		pAppName;
+	deUint32		appVersion;
+	const char*		pEngineName;
+	deUint32		engineVersion;
+	deUint32		apiVersion;
+};
+
+struct VkAllocCallbacks
+{
+	void*				pUserData;
+	PFN_vkAllocFunction	pfnAlloc;
+	PFN_vkFreeFunction	pfnFree;
+};
+
+struct VkInstanceCreateInfo
+{
+	VkStructureType				sType;
+	const void*					pNext;
+	const VkApplicationInfo*	pAppInfo;
+	const VkAllocCallbacks*		pAllocCb;
+	deUint32					layerCount;
+	const char*const*			ppEnabledLayerNames;
+	deUint32					extensionCount;
+	const char*const*			ppEnabledExtensionNames;
+};
+
+struct VkPhysicalDeviceFeatures
+{
+	VkBool32	robustBufferAccess;
+	VkBool32	fullDrawIndexUint32;
+	VkBool32	imageCubeArray;
+	VkBool32	independentBlend;
+	VkBool32	geometryShader;
+	VkBool32	tessellationShader;
+	VkBool32	sampleRateShading;
+	VkBool32	dualSourceBlend;
+	VkBool32	logicOp;
+	VkBool32	multiDrawIndirect;
+	VkBool32	depthClip;
+	VkBool32	depthBiasClamp;
+	VkBool32	fillModeNonSolid;
+	VkBool32	depthBounds;
+	VkBool32	wideLines;
+	VkBool32	largePoints;
+	VkBool32	textureCompressionETC2;
+	VkBool32	textureCompressionASTC_LDR;
+	VkBool32	textureCompressionBC;
+	VkBool32	occlusionQueryNonConservative;
+	VkBool32	pipelineStatisticsQuery;
+	VkBool32	vertexSideEffects;
+	VkBool32	tessellationSideEffects;
+	VkBool32	geometrySideEffects;
+	VkBool32	fragmentSideEffects;
+	VkBool32	shaderTessellationPointSize;
+	VkBool32	shaderGeometryPointSize;
+	VkBool32	shaderImageGatherExtended;
+	VkBool32	shaderStorageImageExtendedFormats;
+	VkBool32	shaderStorageImageMultisample;
+	VkBool32	shaderUniformBufferArrayDynamicIndexing;
+	VkBool32	shaderSampledImageArrayDynamicIndexing;
+	VkBool32	shaderStorageBufferArrayDynamicIndexing;
+	VkBool32	shaderStorageImageArrayDynamicIndexing;
+	VkBool32	shaderClipDistance;
+	VkBool32	shaderCullDistance;
+	VkBool32	shaderFloat64;
+	VkBool32	shaderInt64;
+	VkBool32	shaderInt16;
+	VkBool32	shaderResourceResidency;
+	VkBool32	shaderResourceMinLOD;
+	VkBool32	alphaToOne;
+	VkBool32	sparseBinding;
+	VkBool32	sparseResidencyBuffer;
+	VkBool32	sparseResidencyImage2D;
+	VkBool32	sparseResidencyImage3D;
+	VkBool32	sparseResidency2Samples;
+	VkBool32	sparseResidency4Samples;
+	VkBool32	sparseResidency8Samples;
+	VkBool32	sparseResidency16Samples;
+	VkBool32	sparseResidencyAliased;
+};
+
+struct VkFormatProperties
+{
+	VkFormatFeatureFlags	linearTilingFeatures;
+	VkFormatFeatureFlags	optimalTilingFeatures;
+	VkFormatFeatureFlags	bufferFeatures;
+};
+
+struct VkExtent3D
+{
+	deInt32	width;
+	deInt32	height;
+	deInt32	depth;
+};
+
+struct VkImageFormatProperties
+{
+	VkExtent3D			maxExtent;
+	deUint32			maxMipLevels;
+	deUint32			maxArraySize;
+	VkSampleCountFlags	sampleCounts;
+	VkDeviceSize		maxResourceSize;
+};
+
+struct VkPhysicalDeviceLimits
+{
+	deUint32			maxImageDimension1D;
+	deUint32			maxImageDimension2D;
+	deUint32			maxImageDimension3D;
+	deUint32			maxImageDimensionCube;
+	deUint32			maxImageArrayLayers;
+	VkSampleCountFlags	sampleCounts;
+	deUint32			maxTexelBufferSize;
+	deUint32			maxUniformBufferSize;
+	deUint32			maxStorageBufferSize;
+	deUint32			maxPushConstantsSize;
+	deUint32			maxMemoryAllocationCount;
+	VkDeviceSize		bufferImageGranularity;
+	VkDeviceSize		sparseAddressSpaceSize;
+	deUint32			maxBoundDescriptorSets;
+	deUint32			maxDescriptorSets;
+	deUint32			maxPerStageDescriptorSamplers;
+	deUint32			maxPerStageDescriptorUniformBuffers;
+	deUint32			maxPerStageDescriptorStorageBuffers;
+	deUint32			maxPerStageDescriptorSampledImages;
+	deUint32			maxPerStageDescriptorStorageImages;
+	deUint32			maxDescriptorSetSamplers;
+	deUint32			maxDescriptorSetUniformBuffers;
+	deUint32			maxDescriptorSetUniformBuffersDynamic;
+	deUint32			maxDescriptorSetStorageBuffers;
+	deUint32			maxDescriptorSetStorageBuffersDynamic;
+	deUint32			maxDescriptorSetSampledImages;
+	deUint32			maxDescriptorSetStorageImages;
+	deUint32			maxVertexInputAttributes;
+	deUint32			maxVertexInputBindings;
+	deUint32			maxVertexInputAttributeOffset;
+	deUint32			maxVertexInputBindingStride;
+	deUint32			maxVertexOutputComponents;
+	deUint32			maxTessGenLevel;
+	deUint32			maxTessPatchSize;
+	deUint32			maxTessControlPerVertexInputComponents;
+	deUint32			maxTessControlPerVertexOutputComponents;
+	deUint32			maxTessControlPerPatchOutputComponents;
+	deUint32			maxTessControlTotalOutputComponents;
+	deUint32			maxTessEvaluationInputComponents;
+	deUint32			maxTessEvaluationOutputComponents;
+	deUint32			maxGeometryShaderInvocations;
+	deUint32			maxGeometryInputComponents;
+	deUint32			maxGeometryOutputComponents;
+	deUint32			maxGeometryOutputVertices;
+	deUint32			maxGeometryTotalOutputComponents;
+	deUint32			maxFragmentInputComponents;
+	deUint32			maxFragmentOutputBuffers;
+	deUint32			maxFragmentDualSourceBuffers;
+	deUint32			maxFragmentCombinedOutputResources;
+	deUint32			maxComputeSharedMemorySize;
+	deUint32			maxComputeWorkGroupCount[3];
+	deUint32			maxComputeWorkGroupInvocations;
+	deUint32			maxComputeWorkGroupSize[3];
+	deUint32			subPixelPrecisionBits;
+	deUint32			subTexelPrecisionBits;
+	deUint32			mipmapPrecisionBits;
+	deUint32			maxDrawIndexedIndexValue;
+	deUint32			maxDrawIndirectInstanceCount;
+	VkBool32			primitiveRestartForPatches;
+	float				maxSamplerLodBias;
+	float				maxSamplerAnisotropy;
+	deUint32			maxViewports;
+	deUint32			maxViewportDimensions[2];
+	float				viewportBoundsRange[2];
+	deUint32			viewportSubPixelBits;
+	deUint32			minMemoryMapAlignment;
+	deUint32			minTexelBufferOffsetAlignment;
+	deUint32			minUniformBufferOffsetAlignment;
+	deUint32			minStorageBufferOffsetAlignment;
+	deUint32			minTexelOffset;
+	deUint32			maxTexelOffset;
+	deUint32			minTexelGatherOffset;
+	deUint32			maxTexelGatherOffset;
+	float				minInterpolationOffset;
+	float				maxInterpolationOffset;
+	deUint32			subPixelInterpolationOffsetBits;
+	deUint32			maxFramebufferWidth;
+	deUint32			maxFramebufferHeight;
+	deUint32			maxFramebufferLayers;
+	deUint32			maxFramebufferColorSamples;
+	deUint32			maxFramebufferDepthSamples;
+	deUint32			maxFramebufferStencilSamples;
+	deUint32			maxColorAttachments;
+	deUint32			maxSampledImageColorSamples;
+	deUint32			maxSampledImageDepthSamples;
+	deUint32			maxSampledImageIntegerSamples;
+	deUint32			maxStorageImageSamples;
+	deUint32			maxSampleMaskWords;
+	deUint64			timestampFrequency;
+	deUint32			maxClipDistances;
+	deUint32			maxCullDistances;
+	deUint32			maxCombinedClipAndCullDistances;
+	float				pointSizeRange[2];
+	float				lineWidthRange[2];
+	float				pointSizeGranularity;
+	float				lineWidthGranularity;
+};
+
+struct VkPhysicalDeviceSparseProperties
+{
+	VkBool32	residencyStandard2DBlockShape;
+	VkBool32	residencyStandard2DMSBlockShape;
+	VkBool32	residencyStandard3DBlockShape;
+	VkBool32	residencyAlignedMipSize;
+	VkBool32	residencyNonResident;
+	VkBool32	residencyNonResidentStrict;
+};
+
+struct VkPhysicalDeviceProperties
+{
+	deUint32							apiVersion;
+	deUint32							driverVersion;
+	deUint32							vendorId;
+	deUint32							deviceId;
+	VkPhysicalDeviceType				deviceType;
+	char								deviceName[VK_MAX_PHYSICAL_DEVICE_NAME];
+	deUint8								pipelineCacheUUID[VK_UUID_LENGTH];
+	VkPhysicalDeviceLimits				limits;
+	VkPhysicalDeviceSparseProperties	sparseProperties;
+};
+
+struct VkQueueFamilyProperties
+{
+	VkQueueFlags	queueFlags;
+	deUint32		queueCount;
+	VkBool32		supportsTimestamps;
+};
+
+struct VkMemoryType
+{
+	VkMemoryPropertyFlags	propertyFlags;
+	deUint32				heapIndex;
+};
+
+struct VkMemoryHeap
+{
+	VkDeviceSize		size;
+	VkMemoryHeapFlags	flags;
+};
+
+struct VkPhysicalDeviceMemoryProperties
+{
+	deUint32		memoryTypeCount;
+	VkMemoryType	memoryTypes[VK_MAX_MEMORY_TYPES];
+	deUint32		memoryHeapCount;
+	VkMemoryHeap	memoryHeaps[VK_MAX_MEMORY_HEAPS];
+};
+
+struct VkDeviceQueueCreateInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	deUint32		queueFamilyIndex;
+	deUint32		queueCount;
+};
+
+struct VkDeviceCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	deUint32						queueRecordCount;
+	const VkDeviceQueueCreateInfo*	pRequestedQueues;
+	deUint32						layerCount;
+	const char*const*				ppEnabledLayerNames;
+	deUint32						extensionCount;
+	const char*const*				ppEnabledExtensionNames;
+	const VkPhysicalDeviceFeatures*	pEnabledFeatures;
+};
+
+struct VkExtensionProperties
+{
+	char		extName[VK_MAX_EXTENSION_NAME];
+	deUint32	specVersion;
+};
+
+struct VkLayerProperties
+{
+	char		layerName[VK_MAX_EXTENSION_NAME];
+	deUint32	specVersion;
+	deUint32	implVersion;
+	char		description[VK_MAX_DESCRIPTION];
+};
+
+struct VkMemoryAllocInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	VkDeviceSize	allocationSize;
+	deUint32		memoryTypeIndex;
+};
+
+struct VkMappedMemoryRange
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	VkDeviceMemory	mem;
+	VkDeviceSize	offset;
+	VkDeviceSize	size;
+};
+
+struct VkMemoryRequirements
+{
+	VkDeviceSize	size;
+	VkDeviceSize	alignment;
+	deUint32		memoryTypeBits;
+};
+
+struct VkSparseImageFormatProperties
+{
+	VkImageAspect				aspect;
+	VkExtent3D					imageGranularity;
+	VkSparseImageFormatFlags	flags;
+};
+
+struct VkSparseImageMemoryRequirements
+{
+	VkSparseImageFormatProperties	formatProps;
+	deUint32						imageMipTailStartLOD;
+	VkDeviceSize					imageMipTailSize;
+	VkDeviceSize					imageMipTailOffset;
+	VkDeviceSize					imageMipTailStride;
+};
+
+struct VkSparseMemoryBindInfo
+{
+	VkDeviceSize			rangeOffset;
+	VkDeviceSize			rangeSize;
+	VkDeviceSize			memOffset;
+	VkDeviceMemory			mem;
+	VkSparseMemoryBindFlags	flags;
+};
+
+struct VkImageSubresource
+{
+	VkImageAspect	aspect;
+	deUint32		mipLevel;
+	deUint32		arrayLayer;
+};
+
+struct VkOffset3D
+{
+	deInt32	x;
+	deInt32	y;
+	deInt32	z;
+};
+
+struct VkSparseImageMemoryBindInfo
+{
+	VkImageSubresource		subresource;
+	VkOffset3D				offset;
+	VkExtent3D				extent;
+	VkDeviceSize			memOffset;
+	VkDeviceMemory			mem;
+	VkSparseMemoryBindFlags	flags;
+};
+
+struct VkFenceCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkFenceCreateFlags	flags;
+};
+
+struct VkSemaphoreCreateInfo
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	VkSemaphoreCreateFlags	flags;
+};
+
+struct VkEventCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkEventCreateFlags	flags;
+};
+
+struct VkQueryPoolCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	VkQueryType						queryType;
+	deUint32						slots;
+	VkQueryPipelineStatisticFlags	pipelineStatistics;
+};
+
+struct VkBufferCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkDeviceSize		size;
+	VkBufferUsageFlags	usage;
+	VkBufferCreateFlags	flags;
+	VkSharingMode		sharingMode;
+	deUint32			queueFamilyCount;
+	const deUint32*		pQueueFamilyIndices;
+};
+
+struct VkBufferViewCreateInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	VkBuffer		buffer;
+	VkFormat		format;
+	VkDeviceSize	offset;
+	VkDeviceSize	range;
+};
+
+struct VkImageCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkImageType			imageType;
+	VkFormat			format;
+	VkExtent3D			extent;
+	deUint32			mipLevels;
+	deUint32			arraySize;
+	deUint32			samples;
+	VkImageTiling		tiling;
+	VkImageUsageFlags	usage;
+	VkImageCreateFlags	flags;
+	VkSharingMode		sharingMode;
+	deUint32			queueFamilyCount;
+	const deUint32*		pQueueFamilyIndices;
+	VkImageLayout		initialLayout;
+};
+
+struct VkSubresourceLayout
+{
+	VkDeviceSize	offset;
+	VkDeviceSize	size;
+	VkDeviceSize	rowPitch;
+	VkDeviceSize	depthPitch;
+};
+
+struct VkChannelMapping
+{
+	VkChannelSwizzle	r;
+	VkChannelSwizzle	g;
+	VkChannelSwizzle	b;
+	VkChannelSwizzle	a;
+};
+
+struct VkImageSubresourceRange
+{
+	VkImageAspectFlags	aspectMask;
+	deUint32			baseMipLevel;
+	deUint32			mipLevels;
+	deUint32			baseArrayLayer;
+	deUint32			arraySize;
+};
+
+struct VkImageViewCreateInfo
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	VkImage					image;
+	VkImageViewType			viewType;
+	VkFormat				format;
+	VkChannelMapping		channels;
+	VkImageSubresourceRange	subresourceRange;
+	VkImageViewCreateFlags	flags;
+};
+
+struct VkShaderModuleCreateInfo
+{
+	VkStructureType				sType;
+	const void*					pNext;
+	deUintptr					codeSize;
+	const void*					pCode;
+	VkShaderModuleCreateFlags	flags;
+};
+
+struct VkShaderCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkShaderModule		module;
+	const char*			pName;
+	VkShaderCreateFlags	flags;
+	VkShaderStage		stage;
+};
+
+struct VkPipelineCacheCreateInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	deUintptr		initialSize;
+	const void*		initialData;
+	deUintptr		maxSize;
+};
+
+struct VkSpecializationMapEntry
+{
+	deUint32	constantId;
+	deUintptr	size;
+	deUint32	offset;
+};
+
+struct VkSpecializationInfo
+{
+	deUint32						mapEntryCount;
+	const VkSpecializationMapEntry*	pMap;
+	deUintptr						dataSize;
+	const void*						pData;
+};
+
+struct VkPipelineShaderStageCreateInfo
+{
+	VkStructureType				sType;
+	const void*					pNext;
+	VkShaderStage				stage;
+	VkShader					shader;
+	const VkSpecializationInfo*	pSpecializationInfo;
+};
+
+struct VkVertexInputBindingDescription
+{
+	deUint32				binding;
+	deUint32				strideInBytes;
+	VkVertexInputStepRate	stepRate;
+};
+
+struct VkVertexInputAttributeDescription
+{
+	deUint32	location;
+	deUint32	binding;
+	VkFormat	format;
+	deUint32	offsetInBytes;
+};
+
+struct VkPipelineVertexInputStateCreateInfo
+{
+	VkStructureType								sType;
+	const void*									pNext;
+	deUint32									bindingCount;
+	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
+	deUint32									attributeCount;
+	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+};
+
+struct VkPipelineInputAssemblyStateCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkPrimitiveTopology	topology;
+	VkBool32			primitiveRestartEnable;
+};
+
+struct VkPipelineTessellationStateCreateInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	deUint32		patchControlPoints;
+};
+
+struct VkViewport
+{
+	float	originX;
+	float	originY;
+	float	width;
+	float	height;
+	float	minDepth;
+	float	maxDepth;
+};
+
+struct VkOffset2D
+{
+	deInt32	x;
+	deInt32	y;
+};
+
+struct VkExtent2D
+{
+	deInt32	width;
+	deInt32	height;
+};
+
+struct VkRect2D
+{
+	VkOffset2D	offset;
+	VkExtent2D	extent;
+};
+
+struct VkPipelineViewportStateCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	deUint32			viewportCount;
+	const VkViewport*	pViewports;
+	deUint32			scissorCount;
+	const VkRect2D*		pScissors;
+};
+
+struct VkPipelineRasterStateCreateInfo
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	VkBool32		depthClipEnable;
+	VkBool32		rasterizerDiscardEnable;
+	VkFillMode		fillMode;
+	VkCullMode		cullMode;
+	VkFrontFace		frontFace;
+	VkBool32		depthBiasEnable;
+	float			depthBias;
+	float			depthBiasClamp;
+	float			slopeScaledDepthBias;
+	float			lineWidth;
+};
+
+struct VkPipelineMultisampleStateCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	deUint32			rasterSamples;
+	VkBool32			sampleShadingEnable;
+	float				minSampleShading;
+	const VkSampleMask*	pSampleMask;
+};
+
+struct VkStencilOpState
+{
+	VkStencilOp	stencilFailOp;
+	VkStencilOp	stencilPassOp;
+	VkStencilOp	stencilDepthFailOp;
+	VkCompareOp	stencilCompareOp;
+	deUint32	stencilCompareMask;
+	deUint32	stencilWriteMask;
+	deUint32	stencilReference;
+};
+
+struct VkPipelineDepthStencilStateCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkBool32			depthTestEnable;
+	VkBool32			depthWriteEnable;
+	VkCompareOp			depthCompareOp;
+	VkBool32			depthBoundsTestEnable;
+	VkBool32			stencilTestEnable;
+	VkStencilOpState	front;
+	VkStencilOpState	back;
+	float				minDepthBounds;
+	float				maxDepthBounds;
+};
+
+struct VkPipelineColorBlendAttachmentState
+{
+	VkBool32		blendEnable;
+	VkBlend			srcBlendColor;
+	VkBlend			destBlendColor;
+	VkBlendOp		blendOpColor;
+	VkBlend			srcBlendAlpha;
+	VkBlend			destBlendAlpha;
+	VkBlendOp		blendOpAlpha;
+	VkChannelFlags	channelWriteMask;
+};
+
+struct VkPipelineColorBlendStateCreateInfo
+{
+	VkStructureType								sType;
+	const void*									pNext;
+	VkBool32									alphaToCoverageEnable;
+	VkBool32									alphaToOneEnable;
+	VkBool32									logicOpEnable;
+	VkLogicOp									logicOp;
+	deUint32									attachmentCount;
+	const VkPipelineColorBlendAttachmentState*	pAttachments;
+	float										blendConst[4];
+};
+
+struct VkPipelineDynamicStateCreateInfo
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	deUint32				dynamicStateCount;
+	const VkDynamicState*	pDynamicStates;
+};
+
+struct VkGraphicsPipelineCreateInfo
+{
+	VkStructureType									sType;
+	const void*										pNext;
+	deUint32										stageCount;
+	const VkPipelineShaderStageCreateInfo*			pStages;
+	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
+	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
+	const VkPipelineTessellationStateCreateInfo*	pTessellationState;
+	const VkPipelineViewportStateCreateInfo*		pViewportState;
+	const VkPipelineRasterStateCreateInfo*			pRasterState;
+	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
+	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
+	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
+	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
+	VkPipelineCreateFlags							flags;
+	VkPipelineLayout								layout;
+	VkRenderPass									renderPass;
+	deUint32										subpass;
+	VkPipeline										basePipelineHandle;
+	deInt32											basePipelineIndex;
+};
+
+struct VkComputePipelineCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	VkPipelineShaderStageCreateInfo	stage;
+	VkPipelineCreateFlags			flags;
+	VkPipelineLayout				layout;
+	VkPipeline						basePipelineHandle;
+	deInt32							basePipelineIndex;
+};
+
+struct VkPushConstantRange
+{
+	VkShaderStageFlags	stageFlags;
+	deUint32			start;
+	deUint32			length;
+};
+
+struct VkPipelineLayoutCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	deUint32						descriptorSetCount;
+	const VkDescriptorSetLayout*	pSetLayouts;
+	deUint32						pushConstantRangeCount;
+	const VkPushConstantRange*		pPushConstantRanges;
+};
+
+struct VkSamplerCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkTexFilter			magFilter;
+	VkTexFilter			minFilter;
+	VkTexMipmapMode		mipMode;
+	VkTexAddressMode	addressModeU;
+	VkTexAddressMode	addressModeV;
+	VkTexAddressMode	addressModeW;
+	float				mipLodBias;
+	float				maxAnisotropy;
+	VkBool32			compareEnable;
+	VkCompareOp			compareOp;
+	float				minLod;
+	float				maxLod;
+	VkBorderColor		borderColor;
+	VkBool32			unnormalizedCoordinates;
+};
+
+struct VkDescriptorSetLayoutBinding
+{
+	VkDescriptorType	descriptorType;
+	deUint32			arraySize;
+	VkShaderStageFlags	stageFlags;
+	const VkSampler*	pImmutableSamplers;
+};
+
+struct VkDescriptorSetLayoutCreateInfo
+{
+	VkStructureType						sType;
+	const void*							pNext;
+	deUint32							count;
+	const VkDescriptorSetLayoutBinding*	pBinding;
+};
+
+struct VkDescriptorTypeCount
+{
+	VkDescriptorType	type;
+	deUint32			count;
+};
+
+struct VkDescriptorPoolCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	VkDescriptorPoolUsage			poolUsage;
+	deUint32						maxSets;
+	deUint32						count;
+	const VkDescriptorTypeCount*	pTypeCount;
+};
+
+struct VkDescriptorBufferInfo
+{
+	VkBuffer		buffer;
+	VkDeviceSize	offset;
+	VkDeviceSize	range;
+};
+
+struct VkDescriptorInfo
+{
+	VkBufferView			bufferView;
+	VkSampler				sampler;
+	VkImageView				imageView;
+	VkImageLayout			imageLayout;
+	VkDescriptorBufferInfo	bufferInfo;
+};
+
+struct VkWriteDescriptorSet
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	VkDescriptorSet			destSet;
+	deUint32				destBinding;
+	deUint32				destArrayElement;
+	deUint32				count;
+	VkDescriptorType		descriptorType;
+	const VkDescriptorInfo*	pDescriptors;
+};
+
+struct VkCopyDescriptorSet
+{
+	VkStructureType	sType;
+	const void*		pNext;
+	VkDescriptorSet	srcSet;
+	deUint32		srcBinding;
+	deUint32		srcArrayElement;
+	VkDescriptorSet	destSet;
+	deUint32		destBinding;
+	deUint32		destArrayElement;
+	deUint32		count;
+};
+
+struct VkFramebufferCreateInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkRenderPass		renderPass;
+	deUint32			attachmentCount;
+	const VkImageView*	pAttachments;
+	deUint32			width;
+	deUint32			height;
+	deUint32			layers;
+};
+
+struct VkAttachmentDescription
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	VkFormat						format;
+	deUint32						samples;
+	VkAttachmentLoadOp				loadOp;
+	VkAttachmentStoreOp				storeOp;
+	VkAttachmentLoadOp				stencilLoadOp;
+	VkAttachmentStoreOp				stencilStoreOp;
+	VkImageLayout					initialLayout;
+	VkImageLayout					finalLayout;
+	VkAttachmentDescriptionFlags	flags;
+};
+
+struct VkAttachmentReference
+{
+	deUint32		attachment;
+	VkImageLayout	layout;
+};
+
+struct VkSubpassDescription
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	VkPipelineBindPoint				pipelineBindPoint;
+	VkSubpassDescriptionFlags		flags;
+	deUint32						inputCount;
+	const VkAttachmentReference*	pInputAttachments;
+	deUint32						colorCount;
+	const VkAttachmentReference*	pColorAttachments;
+	const VkAttachmentReference*	pResolveAttachments;
+	VkAttachmentReference			depthStencilAttachment;
+	deUint32						preserveCount;
+	const VkAttachmentReference*	pPreserveAttachments;
+};
+
+struct VkSubpassDependency
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	deUint32				srcSubpass;
+	deUint32				destSubpass;
+	VkPipelineStageFlags	srcStageMask;
+	VkPipelineStageFlags	destStageMask;
+	VkMemoryOutputFlags		outputMask;
+	VkMemoryInputFlags		inputMask;
+	VkBool32				byRegion;
+};
+
+struct VkRenderPassCreateInfo
+{
+	VkStructureType					sType;
+	const void*						pNext;
+	deUint32						attachmentCount;
+	const VkAttachmentDescription*	pAttachments;
+	deUint32						subpassCount;
+	const VkSubpassDescription*		pSubpasses;
+	deUint32						dependencyCount;
+	const VkSubpassDependency*		pDependencies;
+};
+
+struct VkCmdPoolCreateInfo
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	deUint32				queueFamilyIndex;
+	VkCmdPoolCreateFlags	flags;
+};
+
+struct VkCmdBufferCreateInfo
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	VkCmdPool				cmdPool;
+	VkCmdBufferLevel		level;
+	VkCmdBufferCreateFlags	flags;
+};
+
+struct VkCmdBufferBeginInfo
+{
+	VkStructureType				sType;
+	const void*					pNext;
+	VkCmdBufferOptimizeFlags	flags;
+	VkRenderPass				renderPass;
+	deUint32					subpass;
+	VkFramebuffer				framebuffer;
+};
+
+struct VkBufferCopy
+{
+	VkDeviceSize	srcOffset;
+	VkDeviceSize	destOffset;
+	VkDeviceSize	copySize;
+};
+
+struct VkImageSubresourceCopy
+{
+	VkImageAspect	aspect;
+	deUint32		mipLevel;
+	deUint32		arrayLayer;
+	deUint32		arraySize;
+};
+
+struct VkImageCopy
+{
+	VkImageSubresourceCopy	srcSubresource;
+	VkOffset3D				srcOffset;
+	VkImageSubresourceCopy	destSubresource;
+	VkOffset3D				destOffset;
+	VkExtent3D				extent;
+};
+
+struct VkImageBlit
+{
+	VkImageSubresourceCopy	srcSubresource;
+	VkOffset3D				srcOffset;
+	VkExtent3D				srcExtent;
+	VkImageSubresourceCopy	destSubresource;
+	VkOffset3D				destOffset;
+	VkExtent3D				destExtent;
+};
+
+struct VkBufferImageCopy
+{
+	VkDeviceSize			bufferOffset;
+	deUint32				bufferRowLength;
+	deUint32				bufferImageHeight;
+	VkImageSubresourceCopy	imageSubresource;
+	VkOffset3D				imageOffset;
+	VkExtent3D				imageExtent;
+};
+
+union VkClearColorValue
+{
+	float		float32[4];
+	deInt32		int32[4];
+	deUint32	uint32[4];
+};
+
+struct VkClearDepthStencilValue
+{
+	float		depth;
+	deUint32	stencil;
+};
+
+struct VkRect3D
+{
+	VkOffset3D	offset;
+	VkExtent3D	extent;
+};
+
+struct VkImageResolve
+{
+	VkImageSubresourceCopy	srcSubresource;
+	VkOffset3D				srcOffset;
+	VkImageSubresourceCopy	destSubresource;
+	VkOffset3D				destOffset;
+	VkExtent3D				extent;
+};
+
+union VkClearValue
+{
+	VkClearColorValue			color;
+	VkClearDepthStencilValue	depthStencil;
+};
+
+struct VkRenderPassBeginInfo
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkRenderPass		renderPass;
+	VkFramebuffer		framebuffer;
+	VkRect2D			renderArea;
+	deUint32			clearValueCount;
+	const VkClearValue*	pClearValues;
+};
+
+struct VkBufferMemoryBarrier
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkMemoryOutputFlags	outputMask;
+	VkMemoryInputFlags	inputMask;
+	deUint32			srcQueueFamilyIndex;
+	deUint32			destQueueFamilyIndex;
+	VkBuffer			buffer;
+	VkDeviceSize		offset;
+	VkDeviceSize		size;
+};
+
+struct VkDispatchIndirectCmd
+{
+	deUint32	x;
+	deUint32	y;
+	deUint32	z;
+};
+
+struct VkDrawIndexedIndirectCmd
+{
+	deUint32	indexCount;
+	deUint32	instanceCount;
+	deUint32	firstIndex;
+	deInt32		vertexOffset;
+	deUint32	firstInstance;
+};
+
+struct VkDrawIndirectCmd
+{
+	deUint32	vertexCount;
+	deUint32	instanceCount;
+	deUint32	firstVertex;
+	deUint32	firstInstance;
+};
+
+struct VkImageMemoryBarrier
+{
+	VkStructureType			sType;
+	const void*				pNext;
+	VkMemoryOutputFlags		outputMask;
+	VkMemoryInputFlags		inputMask;
+	VkImageLayout			oldLayout;
+	VkImageLayout			newLayout;
+	deUint32				srcQueueFamilyIndex;
+	deUint32				destQueueFamilyIndex;
+	VkImage					image;
+	VkImageSubresourceRange	subresourceRange;
+};
+
+struct VkMemoryBarrier
+{
+	VkStructureType		sType;
+	const void*			pNext;
+	VkMemoryOutputFlags	outputMask;
+	VkMemoryInputFlags	inputMask;
+};
+
diff --git a/external/vulkancts/framework/vulkan/vkTypeUtil.cpp b/external/vulkancts/framework/vulkan/vkTypeUtil.cpp
new file mode 100644
index 0000000..a27f7f1
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkTypeUtil.cpp
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for creating commonly used composite types.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkTypeUtil.hpp"
+
+DE_EMPTY_CPP_FILE
diff --git a/external/vulkancts/framework/vulkan/vkTypeUtil.hpp b/external/vulkancts/framework/vulkan/vkTypeUtil.hpp
new file mode 100644
index 0000000..08a6c73
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkTypeUtil.hpp
@@ -0,0 +1,61 @@
+#ifndef _VKTYPEUTIL_HPP
+#define _VKTYPEUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for creating commonly used composite types.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+
+namespace vk
+{
+
+#include "vkTypeUtil.inl"
+
+inline VkClearValue makeClearValueColorF32 (float r, float g, float b, float a)
+{
+	VkClearValue v;
+	v.color.float32[0] = r;
+	v.color.float32[1] = g;
+	v.color.float32[2] = b;
+	v.color.float32[3] = a;
+	return v;
+}
+
+inline VkChannelMapping makeChannelMappingRGBA (void)
+{
+	return makeChannelMapping(VK_CHANNEL_SWIZZLE_R, VK_CHANNEL_SWIZZLE_G, VK_CHANNEL_SWIZZLE_B, VK_CHANNEL_SWIZZLE_A);
+}
+
+} // vk
+
+#endif // _VKTYPEUTIL_HPP
diff --git a/external/vulkancts/framework/vulkan/vkTypeUtil.inl b/external/vulkancts/framework/vulkan/vkTypeUtil.inl
new file mode 100644
index 0000000..54e6dab
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkTypeUtil.inl
@@ -0,0 +1,284 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+
+inline VkAllocCallbacks makeAllocCallbacks (void* pUserData, PFN_vkAllocFunction pfnAlloc, PFN_vkFreeFunction pfnFree)
+{
+	VkAllocCallbacks res;
+	res.pUserData	= pUserData;
+	res.pfnAlloc	= pfnAlloc;
+	res.pfnFree		= pfnFree;
+	return res;
+}
+
+inline VkExtent3D makeExtent3D (deInt32 width, deInt32 height, deInt32 depth)
+{
+	VkExtent3D res;
+	res.width	= width;
+	res.height	= height;
+	res.depth	= depth;
+	return res;
+}
+
+inline VkMemoryRequirements makeMemoryRequirements (VkDeviceSize size, VkDeviceSize alignment, deUint32 memoryTypeBits)
+{
+	VkMemoryRequirements res;
+	res.size			= size;
+	res.alignment		= alignment;
+	res.memoryTypeBits	= memoryTypeBits;
+	return res;
+}
+
+inline VkSparseMemoryBindInfo makeSparseMemoryBindInfo (VkDeviceSize rangeOffset, VkDeviceSize rangeSize, VkDeviceSize memOffset, VkDeviceMemory mem, VkSparseMemoryBindFlags flags)
+{
+	VkSparseMemoryBindInfo res;
+	res.rangeOffset	= rangeOffset;
+	res.rangeSize	= rangeSize;
+	res.memOffset	= memOffset;
+	res.mem			= mem;
+	res.flags		= flags;
+	return res;
+}
+
+inline VkImageSubresource makeImageSubresource (VkImageAspect aspect, deUint32 mipLevel, deUint32 arrayLayer)
+{
+	VkImageSubresource res;
+	res.aspect		= aspect;
+	res.mipLevel	= mipLevel;
+	res.arrayLayer	= arrayLayer;
+	return res;
+}
+
+inline VkOffset3D makeOffset3D (deInt32 x, deInt32 y, deInt32 z)
+{
+	VkOffset3D res;
+	res.x	= x;
+	res.y	= y;
+	res.z	= z;
+	return res;
+}
+
+inline VkSubresourceLayout makeSubresourceLayout (VkDeviceSize offset, VkDeviceSize size, VkDeviceSize rowPitch, VkDeviceSize depthPitch)
+{
+	VkSubresourceLayout res;
+	res.offset		= offset;
+	res.size		= size;
+	res.rowPitch	= rowPitch;
+	res.depthPitch	= depthPitch;
+	return res;
+}
+
+inline VkChannelMapping makeChannelMapping (VkChannelSwizzle r, VkChannelSwizzle g, VkChannelSwizzle b, VkChannelSwizzle a)
+{
+	VkChannelMapping res;
+	res.r	= r;
+	res.g	= g;
+	res.b	= b;
+	res.a	= a;
+	return res;
+}
+
+inline VkImageSubresourceRange makeImageSubresourceRange (VkImageAspectFlags aspectMask, deUint32 baseMipLevel, deUint32 mipLevels, deUint32 baseArrayLayer, deUint32 arraySize)
+{
+	VkImageSubresourceRange res;
+	res.aspectMask		= aspectMask;
+	res.baseMipLevel	= baseMipLevel;
+	res.mipLevels		= mipLevels;
+	res.baseArrayLayer	= baseArrayLayer;
+	res.arraySize		= arraySize;
+	return res;
+}
+
+inline VkSpecializationMapEntry makeSpecializationMapEntry (deUint32 constantId, deUintptr size, deUint32 offset)
+{
+	VkSpecializationMapEntry res;
+	res.constantId	= constantId;
+	res.size		= size;
+	res.offset		= offset;
+	return res;
+}
+
+inline VkSpecializationInfo makeSpecializationInfo (deUint32 mapEntryCount, const VkSpecializationMapEntry* pMap, deUintptr dataSize, const void* pData)
+{
+	VkSpecializationInfo res;
+	res.mapEntryCount	= mapEntryCount;
+	res.pMap			= pMap;
+	res.dataSize		= dataSize;
+	res.pData			= pData;
+	return res;
+}
+
+inline VkVertexInputBindingDescription makeVertexInputBindingDescription (deUint32 binding, deUint32 strideInBytes, VkVertexInputStepRate stepRate)
+{
+	VkVertexInputBindingDescription res;
+	res.binding			= binding;
+	res.strideInBytes	= strideInBytes;
+	res.stepRate		= stepRate;
+	return res;
+}
+
+inline VkVertexInputAttributeDescription makeVertexInputAttributeDescription (deUint32 location, deUint32 binding, VkFormat format, deUint32 offsetInBytes)
+{
+	VkVertexInputAttributeDescription res;
+	res.location		= location;
+	res.binding			= binding;
+	res.format			= format;
+	res.offsetInBytes	= offsetInBytes;
+	return res;
+}
+
+inline VkViewport makeViewport (float originX, float originY, float width, float height, float minDepth, float maxDepth)
+{
+	VkViewport res;
+	res.originX		= originX;
+	res.originY		= originY;
+	res.width		= width;
+	res.height		= height;
+	res.minDepth	= minDepth;
+	res.maxDepth	= maxDepth;
+	return res;
+}
+
+inline VkOffset2D makeOffset2D (deInt32 x, deInt32 y)
+{
+	VkOffset2D res;
+	res.x	= x;
+	res.y	= y;
+	return res;
+}
+
+inline VkExtent2D makeExtent2D (deInt32 width, deInt32 height)
+{
+	VkExtent2D res;
+	res.width	= width;
+	res.height	= height;
+	return res;
+}
+
+inline VkStencilOpState makeStencilOpState (VkStencilOp stencilFailOp, VkStencilOp stencilPassOp, VkStencilOp stencilDepthFailOp, VkCompareOp stencilCompareOp, deUint32 stencilCompareMask, deUint32 stencilWriteMask, deUint32 stencilReference)
+{
+	VkStencilOpState res;
+	res.stencilFailOp		= stencilFailOp;
+	res.stencilPassOp		= stencilPassOp;
+	res.stencilDepthFailOp	= stencilDepthFailOp;
+	res.stencilCompareOp	= stencilCompareOp;
+	res.stencilCompareMask	= stencilCompareMask;
+	res.stencilWriteMask	= stencilWriteMask;
+	res.stencilReference	= stencilReference;
+	return res;
+}
+
+inline VkPipelineColorBlendAttachmentState makePipelineColorBlendAttachmentState (VkBool32 blendEnable, VkBlend srcBlendColor, VkBlend destBlendColor, VkBlendOp blendOpColor, VkBlend srcBlendAlpha, VkBlend destBlendAlpha, VkBlendOp blendOpAlpha, VkChannelFlags channelWriteMask)
+{
+	VkPipelineColorBlendAttachmentState res;
+	res.blendEnable			= blendEnable;
+	res.srcBlendColor		= srcBlendColor;
+	res.destBlendColor		= destBlendColor;
+	res.blendOpColor		= blendOpColor;
+	res.srcBlendAlpha		= srcBlendAlpha;
+	res.destBlendAlpha		= destBlendAlpha;
+	res.blendOpAlpha		= blendOpAlpha;
+	res.channelWriteMask	= channelWriteMask;
+	return res;
+}
+
+inline VkPushConstantRange makePushConstantRange (VkShaderStageFlags stageFlags, deUint32 start, deUint32 length)
+{
+	VkPushConstantRange res;
+	res.stageFlags	= stageFlags;
+	res.start		= start;
+	res.length		= length;
+	return res;
+}
+
+inline VkDescriptorSetLayoutBinding makeDescriptorSetLayoutBinding (VkDescriptorType descriptorType, deUint32 arraySize, VkShaderStageFlags stageFlags, const VkSampler* pImmutableSamplers)
+{
+	VkDescriptorSetLayoutBinding res;
+	res.descriptorType		= descriptorType;
+	res.arraySize			= arraySize;
+	res.stageFlags			= stageFlags;
+	res.pImmutableSamplers	= pImmutableSamplers;
+	return res;
+}
+
+inline VkDescriptorTypeCount makeDescriptorTypeCount (VkDescriptorType type, deUint32 count)
+{
+	VkDescriptorTypeCount res;
+	res.type	= type;
+	res.count	= count;
+	return res;
+}
+
+inline VkDescriptorBufferInfo makeDescriptorBufferInfo (VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range)
+{
+	VkDescriptorBufferInfo res;
+	res.buffer	= buffer;
+	res.offset	= offset;
+	res.range	= range;
+	return res;
+}
+
+inline VkAttachmentReference makeAttachmentReference (deUint32 attachment, VkImageLayout layout)
+{
+	VkAttachmentReference res;
+	res.attachment	= attachment;
+	res.layout		= layout;
+	return res;
+}
+
+inline VkBufferCopy makeBufferCopy (VkDeviceSize srcOffset, VkDeviceSize destOffset, VkDeviceSize copySize)
+{
+	VkBufferCopy res;
+	res.srcOffset	= srcOffset;
+	res.destOffset	= destOffset;
+	res.copySize	= copySize;
+	return res;
+}
+
+inline VkImageSubresourceCopy makeImageSubresourceCopy (VkImageAspect aspect, deUint32 mipLevel, deUint32 arrayLayer, deUint32 arraySize)
+{
+	VkImageSubresourceCopy res;
+	res.aspect		= aspect;
+	res.mipLevel	= mipLevel;
+	res.arrayLayer	= arrayLayer;
+	res.arraySize	= arraySize;
+	return res;
+}
+
+inline VkClearDepthStencilValue makeClearDepthStencilValue (float depth, deUint32 stencil)
+{
+	VkClearDepthStencilValue res;
+	res.depth	= depth;
+	res.stencil	= stencil;
+	return res;
+}
+
+inline VkDispatchIndirectCmd makeDispatchIndirectCmd (deUint32 x, deUint32 y, deUint32 z)
+{
+	VkDispatchIndirectCmd res;
+	res.x	= x;
+	res.y	= y;
+	res.z	= z;
+	return res;
+}
+
+inline VkDrawIndexedIndirectCmd makeDrawIndexedIndirectCmd (deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance)
+{
+	VkDrawIndexedIndirectCmd res;
+	res.indexCount		= indexCount;
+	res.instanceCount	= instanceCount;
+	res.firstIndex		= firstIndex;
+	res.vertexOffset	= vertexOffset;
+	res.firstInstance	= firstInstance;
+	return res;
+}
+
+inline VkDrawIndirectCmd makeDrawIndirectCmd (deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance)
+{
+	VkDrawIndirectCmd res;
+	res.vertexCount		= vertexCount;
+	res.instanceCount	= instanceCount;
+	res.firstVertex		= firstVertex;
+	res.firstInstance	= firstInstance;
+	return res;
+}
diff --git a/external/vulkancts/framework/vulkan/vkVirtualDeviceInterface.inl b/external/vulkancts/framework/vulkan/vkVirtualDeviceInterface.inl
new file mode 100644
index 0000000..d0febaf
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkVirtualDeviceInterface.inl
@@ -0,0 +1,132 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual void		destroyDevice									(VkDevice device) const = 0;
+virtual VkResult	getDeviceQueue									(VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex, VkQueue* pQueue) const = 0;
+virtual VkResult	queueSubmit										(VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence) const = 0;
+virtual VkResult	queueWaitIdle									(VkQueue queue) const = 0;
+virtual VkResult	deviceWaitIdle									(VkDevice device) const = 0;
+virtual VkResult	allocMemory										(VkDevice device, const VkMemoryAllocInfo* pAllocInfo, VkDeviceMemory* pMem) const = 0;
+virtual void		freeMemory										(VkDevice device, VkDeviceMemory mem) const = 0;
+virtual VkResult	mapMemory										(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) const = 0;
+virtual void		unmapMemory										(VkDevice device, VkDeviceMemory mem) const = 0;
+virtual VkResult	flushMappedMemoryRanges							(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const = 0;
+virtual VkResult	invalidateMappedMemoryRanges					(VkDevice device, deUint32 memRangeCount, const VkMappedMemoryRange* pMemRanges) const = 0;
+virtual VkResult	getDeviceMemoryCommitment						(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes) const = 0;
+virtual VkResult	bindBufferMemory								(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) const = 0;
+virtual VkResult	bindImageMemory									(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) const = 0;
+virtual VkResult	getBufferMemoryRequirements						(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements) const = 0;
+virtual VkResult	getImageMemoryRequirements						(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) const = 0;
+virtual VkResult	getImageSparseMemoryRequirements				(VkDevice device, VkImage image, deUint32* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) const = 0;
+virtual VkResult	getPhysicalDeviceSparseImageFormatProperties	(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, deUint32 samples, VkImageUsageFlags usage, VkImageTiling tiling, deUint32* pNumProperties, VkSparseImageFormatProperties* pProperties) const = 0;
+virtual VkResult	queueBindSparseBufferMemory						(VkQueue queue, VkBuffer buffer, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const = 0;
+virtual VkResult	queueBindSparseImageOpaqueMemory				(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseMemoryBindInfo* pBindInfo) const = 0;
+virtual VkResult	queueBindSparseImageMemory						(VkQueue queue, VkImage image, deUint32 numBindings, const VkSparseImageMemoryBindInfo* pBindInfo) const = 0;
+virtual VkResult	createFence										(VkDevice device, const VkFenceCreateInfo* pCreateInfo, VkFence* pFence) const = 0;
+virtual void		destroyFence									(VkDevice device, VkFence fence) const = 0;
+virtual VkResult	resetFences										(VkDevice device, deUint32 fenceCount, const VkFence* pFences) const = 0;
+virtual VkResult	getFenceStatus									(VkDevice device, VkFence fence) const = 0;
+virtual VkResult	waitForFences									(VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout) const = 0;
+virtual VkResult	createSemaphore									(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore) const = 0;
+virtual void		destroySemaphore								(VkDevice device, VkSemaphore semaphore) const = 0;
+virtual VkResult	queueSignalSemaphore							(VkQueue queue, VkSemaphore semaphore) const = 0;
+virtual VkResult	queueWaitSemaphore								(VkQueue queue, VkSemaphore semaphore) const = 0;
+virtual VkResult	createEvent										(VkDevice device, const VkEventCreateInfo* pCreateInfo, VkEvent* pEvent) const = 0;
+virtual void		destroyEvent									(VkDevice device, VkEvent event) const = 0;
+virtual VkResult	getEventStatus									(VkDevice device, VkEvent event) const = 0;
+virtual VkResult	setEvent										(VkDevice device, VkEvent event) const = 0;
+virtual VkResult	resetEvent										(VkDevice device, VkEvent event) const = 0;
+virtual VkResult	createQueryPool									(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, VkQueryPool* pQueryPool) const = 0;
+virtual void		destroyQueryPool								(VkDevice device, VkQueryPool queryPool) const = 0;
+virtual VkResult	getQueryPoolResults								(VkDevice device, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, deUintptr* pDataSize, void* pData, VkQueryResultFlags flags) const = 0;
+virtual VkResult	createBuffer									(VkDevice device, const VkBufferCreateInfo* pCreateInfo, VkBuffer* pBuffer) const = 0;
+virtual void		destroyBuffer									(VkDevice device, VkBuffer buffer) const = 0;
+virtual VkResult	createBufferView								(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, VkBufferView* pView) const = 0;
+virtual void		destroyBufferView								(VkDevice device, VkBufferView bufferView) const = 0;
+virtual VkResult	createImage										(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage) const = 0;
+virtual void		destroyImage									(VkDevice device, VkImage image) const = 0;
+virtual VkResult	getImageSubresourceLayout						(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const = 0;
+virtual VkResult	createImageView									(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView) const = 0;
+virtual void		destroyImageView								(VkDevice device, VkImageView imageView) const = 0;
+virtual VkResult	createShaderModule								(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule) const = 0;
+virtual void		destroyShaderModule								(VkDevice device, VkShaderModule shaderModule) const = 0;
+virtual VkResult	createShader									(VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader) const = 0;
+virtual void		destroyShader									(VkDevice device, VkShader shader) const = 0;
+virtual VkResult	createPipelineCache								(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache) const = 0;
+virtual void		destroyPipelineCache							(VkDevice device, VkPipelineCache pipelineCache) const = 0;
+virtual deUintptr	getPipelineCacheSize							(VkDevice device, VkPipelineCache pipelineCache) const = 0;
+virtual VkResult	getPipelineCacheData							(VkDevice device, VkPipelineCache pipelineCache, void* pData) const = 0;
+virtual VkResult	mergePipelineCaches								(VkDevice device, VkPipelineCache destCache, deUint32 srcCacheCount, const VkPipelineCache* pSrcCaches) const = 0;
+virtual VkResult	createGraphicsPipelines							(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const = 0;
+virtual VkResult	createComputePipelines							(VkDevice device, VkPipelineCache pipelineCache, deUint32 count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines) const = 0;
+virtual void		destroyPipeline									(VkDevice device, VkPipeline pipeline) const = 0;
+virtual VkResult	createPipelineLayout							(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout) const = 0;
+virtual void		destroyPipelineLayout							(VkDevice device, VkPipelineLayout pipelineLayout) const = 0;
+virtual VkResult	createSampler									(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler) const = 0;
+virtual void		destroySampler									(VkDevice device, VkSampler sampler) const = 0;
+virtual VkResult	createDescriptorSetLayout						(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout) const = 0;
+virtual void		destroyDescriptorSetLayout						(VkDevice device, VkDescriptorSetLayout descriptorSetLayout) const = 0;
+virtual VkResult	createDescriptorPool							(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorPool* pDescriptorPool) const = 0;
+virtual void		destroyDescriptorPool							(VkDevice device, VkDescriptorPool descriptorPool) const = 0;
+virtual VkResult	resetDescriptorPool								(VkDevice device, VkDescriptorPool descriptorPool) const = 0;
+virtual VkResult	allocDescriptorSets								(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, deUint32 count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets) const = 0;
+virtual VkResult	freeDescriptorSets								(VkDevice device, VkDescriptorPool descriptorPool, deUint32 count, const VkDescriptorSet* pDescriptorSets) const = 0;
+virtual void		updateDescriptorSets							(VkDevice device, deUint32 writeCount, const VkWriteDescriptorSet* pDescriptorWrites, deUint32 copyCount, const VkCopyDescriptorSet* pDescriptorCopies) const = 0;
+virtual VkResult	createFramebuffer								(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, VkFramebuffer* pFramebuffer) const = 0;
+virtual void		destroyFramebuffer								(VkDevice device, VkFramebuffer framebuffer) const = 0;
+virtual VkResult	createRenderPass								(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass) const = 0;
+virtual void		destroyRenderPass								(VkDevice device, VkRenderPass renderPass) const = 0;
+virtual VkResult	getRenderAreaGranularity						(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity) const = 0;
+virtual VkResult	createCommandPool								(VkDevice device, const VkCmdPoolCreateInfo* pCreateInfo, VkCmdPool* pCmdPool) const = 0;
+virtual void		destroyCommandPool								(VkDevice device, VkCmdPool cmdPool) const = 0;
+virtual VkResult	resetCommandPool								(VkDevice device, VkCmdPool cmdPool, VkCmdPoolResetFlags flags) const = 0;
+virtual VkResult	createCommandBuffer								(VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, VkCmdBuffer* pCmdBuffer) const = 0;
+virtual void		destroyCommandBuffer							(VkDevice device, VkCmdBuffer commandBuffer) const = 0;
+virtual VkResult	beginCommandBuffer								(VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo) const = 0;
+virtual VkResult	endCommandBuffer								(VkCmdBuffer cmdBuffer) const = 0;
+virtual VkResult	resetCommandBuffer								(VkCmdBuffer cmdBuffer, VkCmdBufferResetFlags flags) const = 0;
+virtual void		cmdBindPipeline									(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) const = 0;
+virtual void		cmdSetViewport									(VkCmdBuffer cmdBuffer, deUint32 viewportCount, const VkViewport* pViewports) const = 0;
+virtual void		cmdSetScissor									(VkCmdBuffer cmdBuffer, deUint32 scissorCount, const VkRect2D* pScissors) const = 0;
+virtual void		cmdSetLineWidth									(VkCmdBuffer cmdBuffer, float lineWidth) const = 0;
+virtual void		cmdSetDepthBias									(VkCmdBuffer cmdBuffer, float depthBias, float depthBiasClamp, float slopeScaledDepthBias) const = 0;
+virtual void		cmdSetBlendConstants							(VkCmdBuffer cmdBuffer, const float blendConst[4]) const = 0;
+virtual void		cmdSetDepthBounds								(VkCmdBuffer cmdBuffer, float minDepthBounds, float maxDepthBounds) const = 0;
+virtual void		cmdSetStencilCompareMask						(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilCompareMask) const = 0;
+virtual void		cmdSetStencilWriteMask							(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilWriteMask) const = 0;
+virtual void		cmdSetStencilReference							(VkCmdBuffer cmdBuffer, VkStencilFaceFlags faceMask, deUint32 stencilReference) const = 0;
+virtual void		cmdBindDescriptorSets							(VkCmdBuffer cmdBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, deUint32 firstSet, deUint32 setCount, const VkDescriptorSet* pDescriptorSets, deUint32 dynamicOffsetCount, const deUint32* pDynamicOffsets) const = 0;
+virtual void		cmdBindIndexBuffer								(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) const = 0;
+virtual void		cmdBindVertexBuffers							(VkCmdBuffer cmdBuffer, deUint32 startBinding, deUint32 bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets) const = 0;
+virtual void		cmdDraw											(VkCmdBuffer cmdBuffer, deUint32 vertexCount, deUint32 instanceCount, deUint32 firstVertex, deUint32 firstInstance) const = 0;
+virtual void		cmdDrawIndexed									(VkCmdBuffer cmdBuffer, deUint32 indexCount, deUint32 instanceCount, deUint32 firstIndex, deInt32 vertexOffset, deUint32 firstInstance) const = 0;
+virtual void		cmdDrawIndirect									(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const = 0;
+virtual void		cmdDrawIndexedIndirect							(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset, deUint32 count, deUint32 stride) const = 0;
+virtual void		cmdDispatch										(VkCmdBuffer cmdBuffer, deUint32 x, deUint32 y, deUint32 z) const = 0;
+virtual void		cmdDispatchIndirect								(VkCmdBuffer cmdBuffer, VkBuffer buffer, VkDeviceSize offset) const = 0;
+virtual void		cmdCopyBuffer									(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkBuffer destBuffer, deUint32 regionCount, const VkBufferCopy* pRegions) const = 0;
+virtual void		cmdCopyImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageCopy* pRegions) const = 0;
+virtual void		cmdBlitImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageBlit* pRegions, VkTexFilter filter) const = 0;
+virtual void		cmdCopyBufferToImage							(VkCmdBuffer cmdBuffer, VkBuffer srcBuffer, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkBufferImageCopy* pRegions) const = 0;
+virtual void		cmdCopyImageToBuffer							(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, deUint32 regionCount, const VkBufferImageCopy* pRegions) const = 0;
+virtual void		cmdUpdateBuffer									(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const deUint32* pData) const = 0;
+virtual void		cmdFillBuffer									(VkCmdBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, deUint32 data) const = 0;
+virtual void		cmdClearColorImage								(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const = 0;
+virtual void		cmdClearDepthStencilImage						(VkCmdBuffer cmdBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rangeCount, const VkImageSubresourceRange* pRanges) const = 0;
+virtual void		cmdClearColorAttachment							(VkCmdBuffer cmdBuffer, deUint32 colorAttachment, VkImageLayout imageLayout, const VkClearColorValue* pColor, deUint32 rectCount, const VkRect3D* pRects) const = 0;
+virtual void		cmdClearDepthStencilAttachment					(VkCmdBuffer cmdBuffer, VkImageAspectFlags aspectMask, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, deUint32 rectCount, const VkRect3D* pRects) const = 0;
+virtual void		cmdResolveImage									(VkCmdBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage destImage, VkImageLayout destImageLayout, deUint32 regionCount, const VkImageResolve* pRegions) const = 0;
+virtual void		cmdSetEvent										(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const = 0;
+virtual void		cmdResetEvent									(VkCmdBuffer cmdBuffer, VkEvent event, VkPipelineStageFlags stageMask) const = 0;
+virtual void		cmdWaitEvents									(VkCmdBuffer cmdBuffer, deUint32 eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, deUint32 memBarrierCount, const void* const* ppMemBarriers) const = 0;
+virtual void		cmdPipelineBarrier								(VkCmdBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags destStageMask, VkBool32 byRegion, deUint32 memBarrierCount, const void* const* ppMemBarriers) const = 0;
+virtual void		cmdBeginQuery									(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot, VkQueryControlFlags flags) const = 0;
+virtual void		cmdEndQuery										(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 slot) const = 0;
+virtual void		cmdResetQueryPool								(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount) const = 0;
+virtual void		cmdWriteTimestamp								(VkCmdBuffer cmdBuffer, VkTimestampType timestampType, VkBuffer destBuffer, VkDeviceSize destOffset) const = 0;
+virtual void		cmdCopyQueryPoolResults							(VkCmdBuffer cmdBuffer, VkQueryPool queryPool, deUint32 startQuery, deUint32 queryCount, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize destStride, VkQueryResultFlags flags) const = 0;
+virtual void		cmdPushConstants								(VkCmdBuffer cmdBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, deUint32 start, deUint32 length, const void* values) const = 0;
+virtual void		cmdBeginRenderPass								(VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents) const = 0;
+virtual void		cmdNextSubpass									(VkCmdBuffer cmdBuffer, VkRenderPassContents contents) const = 0;
+virtual void		cmdEndRenderPass								(VkCmdBuffer cmdBuffer) const = 0;
+virtual void		cmdExecuteCommands								(VkCmdBuffer cmdBuffer, deUint32 cmdBuffersCount, const VkCmdBuffer* pCmdBuffers) const = 0;
diff --git a/external/vulkancts/framework/vulkan/vkVirtualInstanceInterface.inl b/external/vulkancts/framework/vulkan/vkVirtualInstanceInterface.inl
new file mode 100644
index 0000000..86ee5db
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkVirtualInstanceInterface.inl
@@ -0,0 +1,15 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual void				destroyInstance							(VkInstance instance) const = 0;
+virtual VkResult			enumeratePhysicalDevices				(VkInstance instance, deUint32* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) const = 0;
+virtual VkResult			getPhysicalDeviceFeatures				(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures) const = 0;
+virtual VkResult			getPhysicalDeviceFormatProperties		(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties) const = 0;
+virtual VkResult			getPhysicalDeviceImageFormatProperties	(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) const = 0;
+virtual VkResult			getPhysicalDeviceProperties				(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties) const = 0;
+virtual VkResult			getPhysicalDeviceQueueFamilyProperties	(VkPhysicalDevice physicalDevice, deUint32* pCount, VkQueueFamilyProperties* pQueueFamilyProperties) const = 0;
+virtual VkResult			getPhysicalDeviceMemoryProperties		(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties) const = 0;
+virtual PFN_vkVoidFunction	getDeviceProcAddr						(VkDevice device, const char* pName) const = 0;
+virtual VkResult			createDevice							(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice) const = 0;
+virtual VkResult			enumerateDeviceExtensionProperties		(VkPhysicalDevice physicalDevice, const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const = 0;
+virtual VkResult			enumerateDeviceLayerProperties			(VkPhysicalDevice physicalDevice, deUint32* pCount, VkLayerProperties* pProperties) const = 0;
diff --git a/external/vulkancts/framework/vulkan/vkVirtualPlatformInterface.inl b/external/vulkancts/framework/vulkan/vkVirtualPlatformInterface.inl
new file mode 100644
index 0000000..57da028
--- /dev/null
+++ b/external/vulkancts/framework/vulkan/vkVirtualPlatformInterface.inl
@@ -0,0 +1,7 @@
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */
+virtual VkResult			createInstance							(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance) const = 0;
+virtual PFN_vkVoidFunction	getInstanceProcAddr						(VkInstance instance, const char* pName) const = 0;
+virtual VkResult			enumerateInstanceExtensionProperties	(const char* pLayerName, deUint32* pCount, VkExtensionProperties* pProperties) const = 0;
+virtual VkResult			enumerateInstanceLayerProperties		(deUint32* pCount, VkLayerProperties* pProperties) const = 0;
diff --git a/external/vulkancts/gen_framework.py b/external/vulkancts/gen_framework.py
new file mode 100644
index 0000000..2e799fa
--- /dev/null
+++ b/external/vulkancts/gen_framework.py
@@ -0,0 +1,779 @@
+# -*- coding: utf-8 -*-
+
+#-------------------------------------------------------------------------
+# Vulkan CTS
+# ----------
+#
+# Copyright (c) 2015 Google Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and/or associated documentation files (the
+# "Materials"), to deal in the Materials without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Materials, and to
+# permit persons to whom the Materials are furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice(s) and this permission notice shall be
+# included in all copies or substantial portions of the Materials.
+#
+# The Materials are Confidential Information as defined by the
+# Khronos Membership Agreement until designated non-confidential by
+# Khronos, at which point this condition clause shall be removed.
+#
+# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+#
+#-------------------------------------------------------------------------
+
+import os
+import re
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+
+from build.common import DEQP_DIR
+from khr_util.format import indentLines, writeInlFile
+
+VULKAN_DIR = os.path.join(os.path.dirname(__file__), "framework", "vulkan")
+
+INL_HEADER = """\
+/* WARNING: This is auto-generated file. Do not modify, since changes will
+ * be lost! Modify the generating script instead.
+ */\
+"""
+
+PLATFORM_FUNCTIONS	= [
+	"vkCreateInstance",
+	"vkGetInstanceProcAddr",
+	"vkEnumerateInstanceExtensionProperties",
+	"vkEnumerateInstanceLayerProperties",
+]
+INSTANCE_FUNCTIONS	= [
+	"vkDestroyInstance",
+	"vkEnumeratePhysicalDevices",
+	"vkGetPhysicalDeviceFeatures",
+	"vkGetPhysicalDeviceFormatProperties",
+	"vkGetPhysicalDeviceImageFormatProperties",
+	"vkGetPhysicalDeviceLimits",
+	"vkGetPhysicalDeviceProperties",
+	"vkGetPhysicalDeviceQueueFamilyProperties",
+	"vkGetPhysicalDeviceMemoryProperties",
+	"vkEnumerateDeviceExtensionProperties",
+	"vkEnumerateDeviceLayerProperties",
+	"vkCreateDevice",
+	"vkGetDeviceProcAddr",
+]
+
+DEFINITIONS			= [
+	"VK_API_VERSION",
+	"VK_MAX_PHYSICAL_DEVICE_NAME",
+	"VK_MAX_EXTENSION_NAME",
+	"VK_UUID_LENGTH",
+	"VK_MAX_MEMORY_TYPES",
+	"VK_MAX_MEMORY_HEAPS",
+	"VK_MAX_DESCRIPTION",
+	"VK_FALSE",
+	"VK_TRUE",
+	"VK_ATTACHMENT_UNUSED",
+]
+
+class Handle:
+	TYPE_DISP		= 0
+	TYPE_NONDISP	= 1
+
+	def __init__ (self, type, name):
+		self.type	= type
+		self.name	= name
+
+	def getHandleType (self):
+		name = re.sub(r'([A-Z])', r'_\1', self.name)
+		return "HANDLE_TYPE_" + name[4:].upper()
+
+class Enum:
+	def __init__ (self, name, values):
+		self.name	= name
+		self.values	= values
+
+class Bitfield:
+	def __init__ (self, name, values):
+		self.name	= name
+		self.values	= values
+
+class Variable:
+	def __init__ (self, type, name, arraySize = None):
+		self.type		= type
+		self.name		= name
+		self.arraySize	= arraySize
+
+class CompositeType:
+	CLASS_STRUCT	= 0
+	CLASS_UNION		= 1
+
+	def __init__ (self, typeClass, name, members):
+		self.typeClass	= typeClass
+		self.name		= name
+		self.members	= members
+
+	def getClassName (self):
+		names = {CompositeType.CLASS_STRUCT: 'struct', CompositeType.CLASS_UNION: 'union'}
+		return names[self.typeClass]
+
+class Function:
+	TYPE_PLATFORM		= 0 # Not bound to anything
+	TYPE_INSTANCE		= 1 # Bound to VkInstance
+	TYPE_DEVICE			= 2 # Bound to VkDevice
+
+	def __init__ (self, name, returnType, arguments):
+		self.name		= name
+		self.returnType	= returnType
+		self.arguments	= arguments
+
+	def getType (self):
+		if self.name in PLATFORM_FUNCTIONS:
+			return Function.TYPE_PLATFORM
+		elif self.name in INSTANCE_FUNCTIONS:
+			return Function.TYPE_INSTANCE
+		else:
+			return Function.TYPE_DEVICE
+
+class API:
+	def __init__ (self, definitions, handles, enums, bitfields, compositeTypes, functions):
+		self.definitions	= definitions
+		self.handles		= handles
+		self.enums			= enums
+		self.bitfields		= bitfields
+		self.compositeTypes	= compositeTypes
+		self.functions		= functions
+
+def readFile (filename):
+	with open(filename, 'rb') as f:
+		return f.read()
+
+IDENT_PTRN	= r'[a-zA-Z_][a-zA-Z0-9_]*'
+TYPE_PTRN	= r'[a-zA-Z_][a-zA-Z0-9_ \t*]*'
+
+def endswith (s, postfix):
+	return len(s) >= len(postfix) and s[len(s)-len(postfix):] == postfix
+
+def fixupEnumValues (values):
+	fixed = []
+	for name, value in values:
+		if endswith(name, "_BEGIN_RANGE") or endswith(name, "_END_RANGE"):
+			continue
+		fixed.append((name, value))
+	return fixed
+
+def fixupType (type):
+	replacements = [
+			("uint8_t",		"deUint8"),
+			("uint16_t",	"deUint16"),
+			("uint32_t",	"deUint32"),
+			("uint64_t",	"deUint64"),
+			("int8_t",		"deInt8"),
+			("int16_t",		"deInt16"),
+			("int32_t",		"deInt32"),
+			("int64_t",		"deInt64"),
+			("bool32_t",	"deUint32"),
+			("size_t",		"deUintptr"),
+		]
+
+	for src, dst in replacements:
+		type = type.replace(src, dst)
+
+	return type
+
+def fixupFunction (function):
+	fixedArgs		= [Variable(fixupType(a.type), a.name, a.arraySize) for a in function.arguments]
+	fixedReturnType	= fixupType(function.returnType)
+
+	return Function(function.name, fixedReturnType, fixedArgs)
+
+def getInterfaceName (function):
+	assert function.name[:2] == "vk"
+	return function.name[2].lower() + function.name[3:]
+
+def getFunctionTypeName (function):
+	assert function.name[:2] == "vk"
+	return function.name[2:] + "Func"
+
+def getBitEnumNameForBitfield (bitfieldName):
+	assert bitfieldName[-1] == "s"
+	return bitfieldName[:-1] + "Bits"
+
+def getBitfieldNameForBitEnum (bitEnumName):
+	assert bitEnumName[-4:] == "Bits"
+	return bitEnumName[:-4] + "s"
+
+def parsePreprocDefinedValue (src, name):
+	definition = re.search(r'#\s*define\s+' + name + r'\s+([^\n]+)\n', src)
+	if definition is None:
+		raise Exception("No such definition: %s" % name)
+	value = definition.group(1).strip()
+
+	if value == "UINT32_MAX":
+		value = "(~0u)"
+
+	return value
+
+def parseEnum (name, src):
+	keyValuePtrn	= '(' + IDENT_PTRN + r')\s*=\s*([^\s,}]+)\s*[,}]'
+	matches			= re.findall(keyValuePtrn, src)
+
+	return Enum(name, fixupEnumValues(matches))
+
+# \note Parses raw enums, some are mapped to bitfields later
+def parseEnums (src):
+	matches	= re.findall(r'typedef enum\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
+	enums	= []
+
+	for contents, name in matches:
+		enums.append(parseEnum(name, contents))
+
+	return enums
+
+def parseCompositeType (type, name, src):
+	# \todo [pyry] Array support is currently a hack (size coupled with name)
+	typeNamePtrn	= r'(' + TYPE_PTRN + ')(\s' + IDENT_PTRN + r'(\[[^\]]+\])*)\s*;'
+	matches			= re.findall(typeNamePtrn, src)
+	members			= [Variable(fixupType(t.strip()), n.strip()) for t, n, a in matches]
+
+	return CompositeType(type, name, members)
+
+def parseCompositeTypes (src):
+	typeMap	= { 'struct': CompositeType.CLASS_STRUCT, 'union': CompositeType.CLASS_UNION }
+	matches	= re.findall(r'typedef (struct|union)\s*{([^}]*)}\s*(' + IDENT_PTRN + r')\s*;', src)
+	types	= []
+
+	for type, contents, name in matches:
+		types.append(parseCompositeType(typeMap[type], name, contents))
+
+	return types
+
+def parseHandles (src):
+	matches	= re.findall(r'VK_DEFINE(_NONDISP|)_HANDLE\((' + IDENT_PTRN + r')\)[ \t]*[\n\r]', src)
+	handles	= []
+	typeMap	= {'': Handle.TYPE_DISP, '_NONDISP': Handle.TYPE_NONDISP}
+
+	for type, name in matches:
+		handle = Handle(typeMap[type], name)
+		handles.append(handle)
+
+	return handles
+
+def parseArgList (src):
+	typeNamePtrn	= r'(' + TYPE_PTRN + ')(\s' + IDENT_PTRN + r')(\[[^\]]+\])?'
+	args			= []
+
+	for rawArg in src.split(','):
+		m = re.search(typeNamePtrn, rawArg)
+		args.append(Variable(m.group(1).strip(), m.group(2).strip(), m.group(3)))
+
+	return args
+
+def parseFunctions (src):
+	ptrn		= r'(' + TYPE_PTRN + ')VKAPI\s+(' + IDENT_PTRN + r')\s*\(([^)]*)\)\s*;'
+	matches		= re.findall(ptrn, src)
+	functions	= []
+
+	for returnType, name, argList in matches:
+		functions.append(Function(name.strip(), returnType.strip(), parseArgList(argList)))
+
+	return [fixupFunction(f) for f in functions]
+
+def parseBitfieldNames (src):
+	ptrn		= r'typedef\s+VkFlags\s(' + IDENT_PTRN + r')\s*;'
+	matches		= re.findall(ptrn, src)
+
+	return matches
+
+def parseAPI (src):
+	definitions		= [(name, parsePreprocDefinedValue(src, name)) for name in DEFINITIONS]
+	rawEnums		= parseEnums(src)
+	bitfieldNames	= parseBitfieldNames(src)
+	enums			= []
+	bitfields		= []
+	bitfieldEnums	= set([getBitEnumNameForBitfield(n) for n in bitfieldNames])
+
+	for enum in rawEnums:
+		if enum.name in bitfieldEnums:
+			bitfields.append(Bitfield(getBitfieldNameForBitEnum(enum.name), enum.values))
+		else:
+			enums.append(enum)
+
+	return API(
+		definitions		= definitions,
+		handles			= parseHandles(src),
+		enums			= enums,
+		bitfields		= bitfields,
+		compositeTypes	= parseCompositeTypes(src),
+		functions		= parseFunctions(src))
+
+def writeHandleType (api, filename):
+	def gen ():
+		yield "enum HandleType"
+		yield "{"
+		yield "\t%s = 0," % api.handles[0].getHandleType()
+		for handle in api.handles[1:]:
+			yield "\t%s," % handle.getHandleType()
+		yield "\tHANDLE_TYPE_LAST"
+		yield "};"
+		yield ""
+
+	writeInlFile(filename, INL_HEADER, gen())
+
+def getEnumValuePrefix (enum):
+	prefix = enum.name[0]
+	for i in range(1, len(enum.name)):
+		if enum.name[i].isupper():
+			prefix += "_"
+		prefix += enum.name[i].upper()
+	return prefix
+
+def areEnumValuesLinear (enum):
+	curIndex = 0
+	for name, value in enum.values:
+		if int(value) != curIndex:
+			return False
+		curIndex += 1
+	return True
+
+def genEnumSrc (enum):
+	yield "enum %s" % enum.name
+	yield "{"
+
+	for line in indentLines(["\t%s\t= %s," % v for v in enum.values]):
+		yield line
+
+	if areEnumValuesLinear(enum):
+		yield ""
+		yield "\t%s_LAST" % getEnumValuePrefix(enum)
+
+	yield "};"
+
+def genBitfieldSrc (bitfield):
+	yield "enum %s" % getBitEnumNameForBitfield(bitfield.name)
+	yield "{"
+	for line in indentLines(["\t%s\t= %s," % v for v in bitfield.values]):
+		yield line
+	yield "};"
+	yield "typedef deUint32 %s;" % bitfield.name
+
+def genCompositeTypeSrc (type):
+	yield "%s %s" % (type.getClassName(), type.name)
+	yield "{"
+	for line in indentLines(["\t%s\t%s;" % (m.type, m.name) for m in type.members]):
+		yield line
+	yield "};"
+
+def genHandlesSrc (handles):
+	def genLines (handles):
+		for handle in handles:
+			if handle.type == Handle.TYPE_DISP:
+				yield "VK_DEFINE_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
+			elif handle.type == Handle.TYPE_NONDISP:
+				yield "VK_DEFINE_NONDISP_HANDLE\t(%s,\t%s);" % (handle.name, handle.getHandleType())
+
+	for line in indentLines(genLines(handles)):
+		yield line
+
+def writeBasicTypes (api, filename):
+	def gen ():
+		for line in indentLines(["enum { %s\t= %s\t};" % define for define in api.definitions]):
+			yield line
+		yield ""
+		for line in genHandlesSrc(api.handles):
+			yield line
+		yield ""
+		for enum in api.enums:
+			for line in genEnumSrc(enum):
+				yield line
+			yield ""
+		for bitfield in api.bitfields:
+			for line in genBitfieldSrc(bitfield):
+				yield line
+			yield ""
+
+	writeInlFile(filename, INL_HEADER, gen())
+
+def writeCompositeTypes (api, filename):
+	def gen ():
+		for type in api.compositeTypes:
+			for line in genCompositeTypeSrc(type):
+				yield line
+			yield ""
+
+	writeInlFile(filename, INL_HEADER, gen())
+
+def argListToStr (args):
+	return ", ".join("%s %s%s" % (v.type, v.name, v.arraySize if v.arraySize != None else "") for v in args)
+
+def writeInterfaceDecl (api, filename, functionTypes, concrete):
+	def genProtos ():
+		postfix = "" if concrete else " = 0"
+		for function in api.functions:
+			if function.getType() in functionTypes:
+				yield "virtual %s\t%s\t(%s) const%s;" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments), postfix)
+
+	writeInlFile(filename, INL_HEADER, indentLines(genProtos()))
+
+def writeFunctionPtrTypes (api, filename):
+	def genTypes ():
+		for function in api.functions:
+			yield "typedef VK_APICALL %s\t(VK_APIENTRY* %s)\t(%s);" % (function.returnType, getFunctionTypeName(function), argListToStr(function.arguments))
+
+	writeInlFile(filename, INL_HEADER, indentLines(genTypes()))
+
+def writeFunctionPointers (api, filename, functionTypes):
+	writeInlFile(filename, INL_HEADER, indentLines(["%s\t%s;" % (getFunctionTypeName(function), getInterfaceName(function)) for function in api.functions if function.getType() in functionTypes]))
+
+def writeInitFunctionPointers (api, filename, functionTypes):
+	def makeInitFunctionPointers ():
+		for function in api.functions:
+			if function.getType() in functionTypes:
+				yield "m_vk.%s\t= (%s)\tGET_PROC_ADDR(\"%s\");" % (getInterfaceName(function), getFunctionTypeName(function), function.name)
+
+	writeInlFile(filename, INL_HEADER, indentLines(makeInitFunctionPointers()))
+
+def writeFuncPtrInterfaceImpl (api, filename, functionTypes, className):
+	def makeFuncPtrInterfaceImpl ():
+		for function in api.functions:
+			if function.getType() in functionTypes:
+				yield ""
+				yield "%s %s::%s (%s) const" % (function.returnType, className, getInterfaceName(function), argListToStr(function.arguments))
+				yield "{"
+				yield "	%sm_vk.%s(%s);" % ("return " if function.returnType != "void" else "", getInterfaceName(function), ", ".join(a.name for a in function.arguments))
+				yield "}"
+
+	writeInlFile(filename, INL_HEADER, makeFuncPtrInterfaceImpl())
+
+def writeStrUtilProto (api, filename):
+	def makeStrUtilProto ():
+		for line in indentLines(["const char*\tget%sName\t(%s value);" % (enum.name[2:], enum.name) for enum in api.enums]):
+			yield line
+		yield ""
+		for line in indentLines(["inline tcu::Format::Enum<%s>\tget%sStr\t(%s value)\t{ return tcu::Format::Enum<%s>(get%sName, value);\t}" % (e.name, e.name[2:], e.name, e.name, e.name[2:]) for e in api.enums]):
+			yield line
+		yield ""
+		for line in indentLines(["inline std::ostream&\toperator<<\t(std::ostream& s, %s value)\t{ return s << get%sStr(value);\t}" % (e.name, e.name[2:]) for e in api.enums]):
+			yield line
+		yield ""
+		for line in indentLines(["tcu::Format::Bitfield<32>\tget%sStr\t(%s value);" % (bitfield.name[2:], bitfield.name) for bitfield in api.bitfields]):
+			yield line
+		yield ""
+		for line in indentLines(["std::ostream&\toperator<<\t(std::ostream& s, const %s& value);" % (s.name) for s in api.compositeTypes]):
+			yield line
+
+	writeInlFile(filename, INL_HEADER, makeStrUtilProto())
+
+def writeStrUtilImpl (api, filename):
+	def makeStrUtilImpl ():
+		for line in indentLines(["template<> const char*\tgetTypeName<%s>\t(void) { return \"%s\";\t}" % (handle.name, handle.name) for handle in api.handles]):
+			yield line
+
+		for enum in api.enums:
+			yield ""
+			yield "const char* get%sName (%s value)" % (enum.name[2:], enum.name)
+			yield "{"
+			yield "\tswitch (value)"
+			yield "\t{"
+			for line in indentLines(["\t\tcase %s:\treturn \"%s\";" % (n, n) for n, v in enum.values] + ["\t\tdefault:\treturn DE_NULL;"]):
+				yield line
+			yield "\t}"
+			yield "}"
+
+		for bitfield in api.bitfields:
+			yield ""
+			yield "tcu::Format::Bitfield<32> get%sStr (%s value)" % (bitfield.name[2:], bitfield.name)
+			yield "{"
+			yield "\tstatic const tcu::Format::BitDesc s_desc[] ="
+			yield "\t{"
+			for line in indentLines(["\t\ttcu::Format::BitDesc(%s,\t\"%s\")," % (n, n) for n, v in bitfield.values]):
+				yield line
+			yield "\t};"
+			yield "\treturn tcu::Format::Bitfield<32>(value, DE_ARRAY_BEGIN(s_desc), DE_ARRAY_END(s_desc));"
+			yield "}"
+
+		bitfieldTypeNames = set([bitfield.name for bitfield in api.bitfields])
+
+		for type in api.compositeTypes:
+			yield ""
+			yield "std::ostream& operator<< (std::ostream& s, const %s& value)" % type.name
+			yield "{"
+			yield "\ts << \"%s = {\\n\";" % type.name
+			for member in type.members:
+				memberName	= member.name
+				valFmt		= None
+				newLine		= ""
+				if member.type in bitfieldTypeNames:
+					valFmt = "get%sStr(value.%s)" % (member.type[2:], member.name)
+				elif member.type == "const char*" or member.type == "char*":
+					valFmt = "getCharPtrStr(value.%s)" % member.name
+				elif '[' in member.name:
+					baseName = member.name[:member.name.find('[')]
+					if baseName in ["extName", "deviceName", "layerName", "description"]:
+						valFmt = "(const char*)value.%s" % baseName
+					elif member.type == 'char' or member.type == 'deUint8':
+						newLine = "'\\n' << "
+						valFmt = "tcu::formatArray(tcu::Format::HexIterator<%s>(DE_ARRAY_BEGIN(value.%s)), tcu::Format::HexIterator<%s>(DE_ARRAY_END(value.%s)))" % (member.type, baseName, member.type, baseName)
+					else:
+						newLine = "'\\n' << "
+						valFmt = "tcu::formatArray(DE_ARRAY_BEGIN(value.%s), DE_ARRAY_END(value.%s))" % (baseName, baseName)
+					memberName = baseName
+				else:
+					valFmt = "value.%s" % member.name
+				yield ("\ts << \"\\t%s = \" << " % memberName) + newLine + valFmt + " << '\\n';"
+			yield "\ts << '}';"
+			yield "\treturn s;"
+			yield "}"
+
+
+	writeInlFile(filename, INL_HEADER, makeStrUtilImpl())
+
+class ConstructorFunction:
+	def __init__ (self, type, name, objectType, iface, arguments):
+		self.type		= type
+		self.name		= name
+		self.objectType	= objectType
+		self.iface		= iface
+		self.arguments	= arguments
+
+def getConstructorFunctions (api):
+	funcs = []
+	for function in api.functions:
+		if (function.name[:8] == "vkCreate" or function.name == "vkAllocMemory") and not "count" in [a.name for a in function.arguments]:
+			# \todo [pyry] Rather hacky
+			iface = None
+			if function.getType() == Function.TYPE_PLATFORM:
+				iface = Variable("const PlatformInterface&", "vk")
+			elif function.getType() == Function.TYPE_INSTANCE:
+				iface = Variable("const InstanceInterface&", "vk")
+			else:
+				iface = Variable("const DeviceInterface&", "vk")
+			objectType	= function.arguments[-1].type.replace("*", "").strip()
+			arguments	= function.arguments[:-1]
+			funcs.append(ConstructorFunction(function.getType(), getInterfaceName(function), objectType, iface, arguments))
+	return funcs
+
+def writeRefUtilProto (api, filename):
+	functions = getConstructorFunctions(api)
+
+	def makeRefUtilProto ():
+		unindented = []
+		for line in indentLines(["Move<%s>\t%s\t(%s);" % (function.objectType, function.name, argListToStr([function.iface] + function.arguments)) for function in functions]):
+			yield line
+
+	writeInlFile(filename, INL_HEADER, makeRefUtilProto())
+
+def writeRefUtilImpl (api, filename):
+	functions = getConstructorFunctions(api)
+
+	def makeRefUtilImpl ():
+		yield "namespace refdetails"
+		yield "{"
+		yield ""
+
+		for function in api.functions:
+			if function.getType() == Function.TYPE_DEVICE \
+			   and (function.name[:9] == "vkDestroy" or function.name == "vkFreeMemory") \
+			   and not function.name == "vkDestroyDevice":
+				objectType = function.arguments[-1].type
+				yield "template<>"
+				yield "void Deleter<%s>::operator() (%s obj) const" % (objectType, objectType)
+				yield "{"
+				yield "\tm_deviceIface->%s(m_device, obj);" % (getInterfaceName(function))
+				yield "}"
+				yield ""
+
+		yield "} // refdetails"
+		yield ""
+
+		for function in functions:
+			dtorObj = "device" if function.type == Function.TYPE_DEVICE else "object"
+
+			yield "Move<%s> %s (%s)" % (function.objectType, function.name, argListToStr([function.iface] + function.arguments))
+			yield "{"
+			yield "\t%s object = 0;" % function.objectType
+			yield "\tVK_CHECK(vk.%s(%s));" % (function.name, ", ".join([a.name for a in function.arguments] + ["&object"]))
+			yield "\treturn Move<%s>(check<%s>(object), Deleter<%s>(vk, %s));" % (function.objectType, function.objectType, function.objectType, dtorObj)
+			yield "}"
+			yield ""
+
+	writeInlFile(filename, INL_HEADER, makeRefUtilImpl())
+
+def writeNullDriverImpl (api, filename):
+	def genNullDriverImpl ():
+		specialFuncNames	= [
+				"vkCreateGraphicsPipelines",
+				"vkCreateComputePipelines",
+				"vkGetInstanceProcAddr",
+				"vkGetDeviceProcAddr",
+				"vkEnumeratePhysicalDevices",
+				"vkGetPhysicalDeviceProperties",
+				"vkGetPhysicalDeviceQueueFamilyProperties",
+				"vkGetPhysicalDeviceMemoryProperties",
+				"vkGetBufferMemoryRequirements",
+				"vkGetImageMemoryRequirements",
+				"vkMapMemory",
+				"vkAllocDescriptorSets",
+				"vkFreeDescriptorSets",
+			]
+		specialFuncs		= [f for f in api.functions if f.name in specialFuncNames]
+		createFuncs			= [f for f in api.functions if (f.name[:8] == "vkCreate" or f.name == "vkAllocMemory") and not f in specialFuncs]
+		destroyFuncs		= [f for f in api.functions if (f.name[:9] == "vkDestroy" or f.name == "vkFreeMemory") and not f in specialFuncs]
+		dummyFuncs			= [f for f in api.functions if f not in specialFuncs + createFuncs + destroyFuncs]
+
+		def getHandle (name):
+			for handle in api.handles:
+				if handle.name == name:
+					return handle
+			raise Exception("No such handle: %s" % name)
+
+		for function in createFuncs:
+			objectType	= function.arguments[-1].type.replace("*", "").strip()
+			argsStr		= ", ".join([a.name for a in function.arguments[:-1]])
+
+			yield "%s %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
+			yield "{"
+
+			if getHandle(objectType).type == Handle.TYPE_NONDISP:
+				yield "\tVK_NULL_RETURN(*%s = %s((deUint64)(deUintptr)new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+			else:
+				yield "\tVK_NULL_RETURN(*%s = reinterpret_cast<%s>(new %s(%s)));" % (function.arguments[-1].name, objectType, objectType[2:], argsStr)
+
+			yield "}"
+			yield ""
+
+		for function in destroyFuncs:
+			yield "%s %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
+			yield "{"
+			for arg in function.arguments[:-1]:
+				yield "\tDE_UNREF(%s);" % arg.name
+
+			if getHandle(function.arguments[-1].type).type == Handle.TYPE_NONDISP:
+				yield "\tdelete reinterpret_cast<%s*>((deUintptr)%s.getInternal());" % (function.arguments[-1].type[2:], function.arguments[-1].name)
+			else:
+				yield "\tdelete reinterpret_cast<%s*>(%s);" % (function.arguments[-1].type[2:], function.arguments[-1].name)
+
+			yield "}"
+			yield ""
+
+		for function in dummyFuncs:
+			yield "%s %s (%s)" % (function.returnType, getInterfaceName(function), argListToStr(function.arguments))
+			yield "{"
+			for arg in function.arguments:
+				yield "\tDE_UNREF(%s);" % arg.name
+			if function.returnType != "void":
+				yield "\treturn VK_SUCCESS;"
+			yield "}"
+			yield ""
+
+		def genFuncEntryTable (type, name):
+			funcs = [f for f in api.functions if f.getType() == type]
+
+			yield "static const tcu::StaticFunctionLibrary::Entry %s[] =" % name
+			yield "{"
+			for line in indentLines(["\tVK_NULL_FUNC_ENTRY(%s,\t%s)," % (function.name, getInterfaceName(function)) for function in funcs]):
+				yield line
+			yield "};"
+			yield ""
+
+		# Func tables
+		for line in genFuncEntryTable(Function.TYPE_PLATFORM, "s_platformFunctions"):
+			yield line
+
+		for line in genFuncEntryTable(Function.TYPE_INSTANCE, "s_instanceFunctions"):
+			yield line
+
+		for line in genFuncEntryTable(Function.TYPE_DEVICE, "s_deviceFunctions"):
+			yield line
+
+
+	writeInlFile(filename, INL_HEADER, genNullDriverImpl())
+
+def writeTypeUtil (api, filename):
+	# Structs filled by API queries are not often used in test code
+	QUERY_RESULT_TYPES = set([
+			"VkPhysicalDeviceFeatures",
+			"VkPhysicalDeviceLimits",
+			"VkFormatProperties",
+			"VkImageFormatProperties",
+			"VkPhysicalDeviceSparseProperties",
+			"VkQueueFamilyProperties",
+			"VkMemoryType",
+			"VkMemoryHeap",
+		])
+	COMPOSITE_TYPES = set([t.name for t in api.compositeTypes])
+
+	def isSimpleStruct (type):
+		def hasArrayMember (type):
+			for member in type.members:
+				if "[" in member.name:
+					return True
+			return False
+
+		def hasCompositeMember (type):
+			for member in type.members:
+				if member.type in COMPOSITE_TYPES:
+					return True
+			return False
+
+		return type.typeClass == CompositeType.CLASS_STRUCT and \
+			   type.members[0].type != "VkStructureType" and \
+			   not type.name in QUERY_RESULT_TYPES and \
+			   not hasArrayMember(type) and \
+			   not hasCompositeMember(type)
+
+	def gen ():
+		for type in api.compositeTypes:
+			if not isSimpleStruct(type):
+				continue
+
+			yield ""
+			yield "inline %s make%s (%s)" % (type.name, type.name[2:], argListToStr(type.members))
+			yield "{"
+			yield "\t%s res;" % type.name
+			for line in indentLines(["\tres.%s\t= %s;" % (m.name, m.name) for m in type.members]):
+				yield line
+			yield "\treturn res;"
+			yield "}"
+
+	writeInlFile(filename, INL_HEADER, gen())
+
+if __name__ == "__main__":
+	src				= readFile(sys.argv[1])
+	api				= parseAPI(src)
+	platformFuncs	= set([Function.TYPE_PLATFORM])
+	instanceFuncs	= set([Function.TYPE_INSTANCE])
+	deviceFuncs		= set([Function.TYPE_DEVICE])
+
+	writeHandleType				(api, os.path.join(VULKAN_DIR, "vkHandleType.inl"))
+	writeBasicTypes				(api, os.path.join(VULKAN_DIR, "vkBasicTypes.inl"))
+	writeCompositeTypes			(api, os.path.join(VULKAN_DIR, "vkStructTypes.inl"))
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkVirtualPlatformInterface.inl"),		functionTypes = platformFuncs,	concrete = False)
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkVirtualInstanceInterface.inl"),		functionTypes = instanceFuncs,	concrete = False)
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkVirtualDeviceInterface.inl"),			functionTypes = deviceFuncs,	concrete = False)
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkConcretePlatformInterface.inl"),		functionTypes = platformFuncs,	concrete = True)
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkConcreteInstanceInterface.inl"),		functionTypes = instanceFuncs,	concrete = True)
+	writeInterfaceDecl			(api, os.path.join(VULKAN_DIR, "vkConcreteDeviceInterface.inl"),		functionTypes = deviceFuncs,	concrete = True)
+	writeFunctionPtrTypes		(api, os.path.join(VULKAN_DIR, "vkFunctionPointerTypes.inl"))
+	writeFunctionPointers		(api, os.path.join(VULKAN_DIR, "vkPlatformFunctionPointers.inl"),		functionTypes = platformFuncs)
+	writeFunctionPointers		(api, os.path.join(VULKAN_DIR, "vkInstanceFunctionPointers.inl"),		functionTypes = instanceFuncs)
+	writeFunctionPointers		(api, os.path.join(VULKAN_DIR, "vkDeviceFunctionPointers.inl"),			functionTypes = deviceFuncs)
+	writeInitFunctionPointers	(api, os.path.join(VULKAN_DIR, "vkInitPlatformFunctionPointers.inl"),	functionTypes = platformFuncs)
+	writeInitFunctionPointers	(api, os.path.join(VULKAN_DIR, "vkInitInstanceFunctionPointers.inl"),	functionTypes = instanceFuncs)
+	writeInitFunctionPointers	(api, os.path.join(VULKAN_DIR, "vkInitDeviceFunctionPointers.inl"),		functionTypes = deviceFuncs)
+	writeFuncPtrInterfaceImpl	(api, os.path.join(VULKAN_DIR, "vkPlatformDriverImpl.inl"),				functionTypes = platformFuncs,	className = "PlatformDriver")
+	writeFuncPtrInterfaceImpl	(api, os.path.join(VULKAN_DIR, "vkInstanceDriverImpl.inl"),				functionTypes = instanceFuncs,	className = "InstanceDriver")
+	writeFuncPtrInterfaceImpl	(api, os.path.join(VULKAN_DIR, "vkDeviceDriverImpl.inl"),				functionTypes = deviceFuncs,	className = "DeviceDriver")
+	writeStrUtilProto			(api, os.path.join(VULKAN_DIR, "vkStrUtil.inl"))
+	writeStrUtilImpl			(api, os.path.join(VULKAN_DIR, "vkStrUtilImpl.inl"))
+	writeRefUtilProto			(api, os.path.join(VULKAN_DIR, "vkRefUtil.inl"))
+	writeRefUtilImpl			(api, os.path.join(VULKAN_DIR, "vkRefUtilImpl.inl"))
+	writeNullDriverImpl			(api, os.path.join(VULKAN_DIR, "vkNullDriverImpl.inl"))
+	writeTypeUtil				(api, os.path.join(VULKAN_DIR, "vkTypeUtil.inl"))
diff --git a/external/vulkancts/modules/vulkan/CMakeLists.txt b/external/vulkancts/modules/vulkan/CMakeLists.txt
new file mode 100644
index 0000000..71e9fa7
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/CMakeLists.txt
@@ -0,0 +1,59 @@
+# dEQP-VK
+
+add_subdirectory(api)
+add_subdirectory(pipeline)
+add_subdirectory(binding_model)
+add_subdirectory(spirv_assembly)
+
+include_directories(
+	api
+	pipeline
+	binding_model
+	spirv_assembly
+	)
+
+set(DEQP_VK_COMMON_SRCS
+	vktTestCase.cpp
+	vktTestCase.hpp
+	vktTestCaseUtil.cpp
+	vktTestCaseUtil.hpp
+	vktTestPackage.cpp
+	vktTestPackage.hpp
+	vktInfo.cpp
+	vktInfo.hpp
+	vktShaderLibrary.cpp
+	vktShaderLibrary.hpp
+	vktRenderPassTests.cpp
+	vktRenderPassTests.hpp
+	)
+
+set(DEQP_VK_COMMON_LIBS
+	tcutil
+	vkutil
+	glutil
+	deqp-vk-api
+	deqp-vk-pipeline
+	deqp-vk-binding-model
+	deqp-vk-spirv-assembly
+	)
+
+if (DE_OS_IS_WIN32 OR DE_OS_IS_UNIX OR DE_OS_IS_OSX)
+	add_library(deqp-vk-common STATIC ${DEQP_VK_COMMON_SRCS})
+	target_link_libraries(deqp-vk-common ${DEQP_VK_COMMON_LIBS})
+
+	add_executable(vk-build-programs vktBuildPrograms.cpp)
+	target_link_libraries(vk-build-programs deqp-vk-common)
+	add_dependencies(vk-build-programs deqp-vk-data)
+
+	set(DEQP_VK_SRCS	)
+	set(DEQP_VK_LIBS	deqp-vk-common)
+
+else ()
+	set(DEQP_VK_SRCS	${DEQP_VK_COMMON_SRCS})
+	set(DEQP_VK_LIBS	${DEQP_VK_COMMON_LIBS})
+
+endif ()
+
+add_deqp_module(deqp-vk "${DEQP_VK_SRCS}" "${DEQP_VK_LIBS}" vktTestPackageEntry.cpp)
+
+add_data_dir(deqp-vk ../../data/vulkan	vulkan)
diff --git a/external/vulkancts/modules/vulkan/api/CMakeLists.txt b/external/vulkancts/modules/vulkan/api/CMakeLists.txt
new file mode 100644
index 0000000..45ff205
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/CMakeLists.txt
@@ -0,0 +1,22 @@
+# API layer tests
+
+include_directories(..)
+
+set(DEQP_VK_API_SRCS
+	vktApiTests.cpp
+	vktApiTests.hpp
+	vktApiSmokeTests.cpp
+	vktApiSmokeTests.hpp
+	vktApiDeviceInitializationTests.cpp
+	vktApiDeviceInitializationTests.hpp
+	vktApiObjectManagementTests.cpp
+	vktApiObjectManagementTests.hpp
+	)
+
+set(DEQP_VK_API_LIBS
+	tcutil
+	vkutil
+	)
+
+add_library(deqp-vk-api STATIC ${DEQP_VK_API_SRCS})
+target_link_libraries(deqp-vk-api ${DEQP_VK_API_LIBS})
diff --git a/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.cpp
new file mode 100644
index 0000000..63d0159
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.cpp
@@ -0,0 +1,553 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Device Initialization Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiDeviceInitializationTests.hpp"
+#include "vktTestCaseUtil.hpp"
+
+#include "vkDefs.hpp"
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkApiVersion.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuResultCollector.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+
+#include <vector>
+
+namespace vkt
+{
+namespace api
+{
+
+namespace
+{
+
+using namespace vk;
+using namespace std;
+using std::vector;
+using tcu::TestLog;
+
+tcu::TestStatus createInstanceTest (Context& context)
+{
+	tcu::TestLog&				log						= context.getTestContext().getLog();
+	tcu::ResultCollector		resultCollector			(log);
+	const char*					appNames[]				= { "appName", DE_NULL, "",  "app, name", "app(\"name\"", "app~!@#$%^&*()_+name", "app\nName", "app\r\nName" };
+	const char*					engineNames[]			= { "engineName", DE_NULL, "",  "engine. name", "engine\"(name)", "eng~!@#$%^&*()_+name", "engine\nName", "engine\r\nName" };
+	const deUint32				appVersions[]			= { 0, 1, (deUint32)-1 };
+	const deUint32				engineVersions[]		= { 0, 1, (deUint32)-1 };
+	const PlatformInterface&	platformInterface		= context.getPlatformInterface();
+	vector<VkApplicationInfo>	appInfos;
+
+	// test over appName
+	for (int appNameNdx = 0; appNameNdx < DE_LENGTH_OF_ARRAY(appNames); appNameNdx++)
+	{
+		const VkApplicationInfo appInfo =
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,		// VkStructureType				sType;
+			DE_NULL,								// const void*					pNext;
+			appNames[appNameNdx],					// const char*					pAppName;
+			0u,										// deUint32						appVersion;
+			"engineName",							// const char*					pEngineName;
+			0u,										// deUint32						engineVersion;
+			VK_API_VERSION,							// deUint32						apiVersion;
+		};
+
+		appInfos.push_back(appInfo);
+	}
+
+	// test over engineName
+	for (int engineNameNdx = 0; engineNameNdx < DE_LENGTH_OF_ARRAY(engineNames); engineNameNdx++)
+	{
+		const VkApplicationInfo appInfo =
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,		// VkStructureType				sType;
+			DE_NULL,								// const void*					pNext;
+			"appName",								// const char*					pAppName;
+			0u,										// deUint32						appVersion;
+			engineNames[engineNameNdx],				// const char*					pEngineName;
+			0u,										// deUint32						engineVersion;
+			VK_API_VERSION,							// deUint32						apiVersion;
+		};
+
+		appInfos.push_back(appInfo);
+	}
+
+	// test over appVersion
+	for (int appVersionNdx = 0; appVersionNdx < DE_LENGTH_OF_ARRAY(appVersions); appVersionNdx++)
+	{
+		const VkApplicationInfo appInfo =
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,		// VkStructureType				sType;
+			DE_NULL,								// const void*					pNext;
+			"appName",								// const char*					pAppName;
+			appVersions[appVersionNdx],				// deUint32						appVersion;
+			"engineName",							// const char*					pEngineName;
+			0u,										// deUint32						engineVersion;
+			VK_API_VERSION,							// deUint32						apiVersion;
+		};
+
+		appInfos.push_back(appInfo);
+	}
+
+	// test over engineVersion
+	for (int engineVersionNdx = 0; engineVersionNdx < DE_LENGTH_OF_ARRAY(engineVersions); engineVersionNdx++)
+	{
+		const VkApplicationInfo appInfo =
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,		// VkStructureType				sType;
+			DE_NULL,								// const void*					pNext;
+			"appName",								// const char*					pAppName;
+			0u,										// deUint32						appVersion;
+			"engineName",							// const char*					pEngineName;
+			engineVersions[engineVersionNdx],		// deUint32						engineVersion;
+			VK_API_VERSION,							// deUint32						apiVersion;
+		};
+
+		appInfos.push_back(appInfo);
+	}
+
+	// run the tests!
+	for (size_t appInfoNdx = 0; appInfoNdx < appInfos.size(); ++appInfoNdx)
+	{
+		const VkApplicationInfo&		appInfo					= appInfos[appInfoNdx];
+		const VkInstanceCreateInfo		instanceCreateInfo		=
+		{
+			VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,	// VkStructureType				sType;
+			DE_NULL,								// const void*					pNext;
+			&appInfo,								// const VkApplicationInfo*		pAppInfo;
+			DE_NULL,								// const VkAllocCallbacks*		pAllocCb;
+			0u,										// deUint32						layerCount;
+			DE_NULL,								// const char*const*			ppEnabledLayernames;
+			0u,										// deUint32						extensionCount;
+			DE_NULL,								// const char*const*			ppEnabledExtensionNames;
+		};
+
+		log << TestLog::Message << "Creating instance with appInfo: " << appInfo << TestLog::EndMessage;
+
+		try
+		{
+			const Unique<VkInstance> instance(createInstance(platformInterface, &instanceCreateInfo));
+			log << TestLog::Message << "Succeeded" << TestLog::EndMessage;
+		}
+		catch (const vk::Error& err)
+		{
+			resultCollector.fail("Failed, Error code: " + de::toString(err.getMessage()));
+		}
+	}
+
+	return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
+}
+
+tcu::TestStatus createInstanceWithInvalidApiVersionTest (Context& context)
+{
+	tcu::TestLog&				log					= context.getTestContext().getLog();
+	tcu::ResultCollector		resultCollector		(log);
+	const PlatformInterface&	platformInterface	= context.getPlatformInterface();
+	const ApiVersion			apiVersion			= unpackVersion(VK_API_VERSION);
+	const deUint32				invalidMajorVersion	= (1 << 10) - 1;
+	const deUint32				invalidMinorVersion	= (1 << 10) - 1;
+	const deUint32				invalidPatchNum		= (1 << 12) - 1;
+	vector<ApiVersion>			invalidApiVersions;
+
+	invalidApiVersions.push_back(ApiVersion(invalidMajorVersion, apiVersion.minorNum, apiVersion.patchNum));
+	invalidApiVersions.push_back(ApiVersion(apiVersion.majorNum, invalidMinorVersion, apiVersion.patchNum));
+	invalidApiVersions.push_back(ApiVersion(apiVersion.majorNum, apiVersion.minorNum, invalidPatchNum));
+
+	for (size_t apiVersionNdx = 0; apiVersionNdx < invalidApiVersions.size(); apiVersionNdx++)
+	{
+		const VkApplicationInfo appInfo					=
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,			// VkStructureType				sType;
+			DE_NULL,									// const void*					pNext;
+			"appName",									// const char*					pAppName;
+			0u,											// deUint32						appVersion;
+			"engineName",								// const char*					pEngineName;
+			0u,											// deUint32						engineVersion;
+			pack(invalidApiVersions[apiVersionNdx]),	// deUint32						apiVersion;
+		};
+		const VkInstanceCreateInfo instanceCreateInfo	=
+		{
+			VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,		// VkStructureType				sType;
+			DE_NULL,									// const void*					pNext;
+			&appInfo,									// const VkApplicationInfo*		pAppInfo;
+			DE_NULL,									// const VkAllocCallbacks*		pAllocCb;
+			0u,											// deUint32						layerCount;
+			DE_NULL,									// const char*const*			ppEnabledLayernames;
+			0u,											// deUint32						extensionCount;
+			DE_NULL,									// const char*const*			ppEnabledExtensionNames;
+		};
+
+
+		log << TestLog::Message
+			<<"VK_API_VERSION defined in vulkan.h: " << apiVersion
+			<< ", api version used to create instance: " << invalidApiVersions[apiVersionNdx]
+			<< TestLog::EndMessage;
+
+		try
+		{
+			const Unique<VkInstance> instance(createInstance(platformInterface, &instanceCreateInfo));
+
+			resultCollector.fail("Fail, instance creation with invalid apiVersion is not rejected");
+		}
+		catch (const tcu::NotSupportedError&)
+		{
+			log << TestLog::Message << "Pass, instance creation with invalid apiVersion is rejected" << TestLog::EndMessage;
+		}
+	}
+
+	return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
+}
+
+tcu::TestStatus createInstanceWithUnsupportedExtensionsTest (Context& context)
+{
+	tcu::TestLog&						log						= context.getTestContext().getLog();
+	const PlatformInterface&			platformInterface		= context.getPlatformInterface();
+	const char*							enabledExtensions[]		= {"VK_UNSUPPORTED_EXTENSION", "THIS_IS_NOT_AN_EXTENSION"};
+	const VkApplicationInfo				appInfo					=
+	{
+		VK_STRUCTURE_TYPE_APPLICATION_INFO,						// VkStructureType				sType;
+		DE_NULL,												// const void*					pNext;
+		"appName",												// const char*					pAppName;
+		0u,														// deUint32						appVersion;
+		"engineName",											// const char*					pEngineName;
+		0u,														// deUint32						engineVersion;
+		VK_API_VERSION,											// deUint32						apiVersion;
+	};
+	const VkInstanceCreateInfo			instanceCreateInfo		=
+	{
+		VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,					// VkStructureType				sType;
+		DE_NULL,												// const void*					pNext;
+		&appInfo,												// const VkApplicationInfo*		pAppInfo;
+		DE_NULL,												// const VkAllocCallbacks*		pAllocCb;
+		0u,														// deUint32						layerCount;
+		DE_NULL,												// const char*const*			ppEnabledLayernames;
+		DE_LENGTH_OF_ARRAY(enabledExtensions),					// deUint32						extensionCount;
+		enabledExtensions,										// const char*const*			ppEnabledExtensionNames;
+	};
+
+	try
+	{
+		Unique<VkInstance> instance(createInstance(platformInterface, &instanceCreateInfo));
+
+		log << TestLog::Message << "Enabled extensions are: " << TestLog::EndMessage;
+
+		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(enabledExtensions); ndx++)
+			log << TestLog::Message << enabledExtensions[ndx] <<  TestLog::EndMessage;
+
+		return tcu::TestStatus::fail("Fail, creating instance with unsupported extensions succeeded.");
+	}
+	catch (const tcu::NotSupportedError&)
+	{
+		return tcu::TestStatus::pass("Pass, creating instance with unsupported extension was rejected.");
+	}
+}
+
+tcu::TestStatus createDeviceTest (Context& context)
+{
+	const PlatformInterface&	platformInterface		= context.getPlatformInterface();
+	const Unique<VkInstance>	instance				(createDefaultInstance(platformInterface));
+	const InstanceDriver		instanceDriver			(platformInterface, instance.get());
+	const VkPhysicalDevice		physicalDevice			= chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
+	const deUint32				queueFamilyIndex		= 0;
+	const deUint32				queueCount				= 1;
+	const deUint32				queueIndex				= 0;
+	VkDeviceQueueCreateInfo		deviceQueueCreateInfo	=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+		DE_NULL,
+		queueFamilyIndex,						//queueFamilyIndex;
+		queueCount								//queueCount;
+	};
+	VkDeviceCreateInfo			deviceCreateInfo		=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,	//sType;
+		DE_NULL,								//pNext;
+		1,										//queueRecordCount;
+		&deviceQueueCreateInfo,					//pRequestedQueues;
+		0,										//layerCount;
+		DE_NULL,								//ppEnabledLayerNames;
+		0,										//extensionCount;
+		DE_NULL,								//ppEnabledExtensionNames;
+		DE_NULL,								//pEnabledFeatures;
+	};
+
+	const Unique<VkDevice>			device					(createDevice(instanceDriver, physicalDevice, &deviceCreateInfo));
+	const DeviceDriver				deviceDriver			(instanceDriver, device.get());
+	VkQueue							queue;
+
+	VK_CHECK(deviceDriver.getDeviceQueue(device.get(), queueFamilyIndex, queueIndex, &queue));
+	VK_CHECK(deviceDriver.queueWaitIdle(queue));
+
+	return tcu::TestStatus::pass("Pass");
+}
+
+tcu::TestStatus createMultipleDevicesTest (Context& context)
+{
+	tcu::TestLog&										log						= context.getTestContext().getLog();
+	tcu::ResultCollector								resultCollector			(log);
+	const int											numDevices				= 5;
+	const PlatformInterface&							platformInterface		= context.getPlatformInterface();
+	const Unique<VkInstance>							instance				(createDefaultInstance(platformInterface));
+	const InstanceDriver								instanceDriver			(platformInterface, instance.get());
+	const VkPhysicalDevice								physicalDevice			= chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
+	const deUint32										queueFamilyIndex		= 0;
+	const deUint32										queueCount				= 1;
+	const deUint32										queueIndex				= 0;
+	const VkDeviceQueueCreateInfo						deviceQueueCreateInfo	=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+		DE_NULL,
+		queueFamilyIndex,								//queueFamilyIndex;
+		queueCount										//queueCount;
+	};
+	const VkDeviceCreateInfo							deviceCreateInfo		=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,			//sType;
+		DE_NULL,										//pNext;
+		1,												//queueRecordCount;
+		&deviceQueueCreateInfo,							//pRequestedQueues;
+		0,												//layerCount;
+		DE_NULL,										//ppEnabledLayerNames;
+		0,												//extensionCount;
+		DE_NULL,										//ppEnabledExtensionNames;
+		DE_NULL,										//pEnabledFeatures;
+	};
+	vector<VkDevice>									devices(numDevices, (VkDevice)DE_NULL);
+
+	try
+	{
+		for (int deviceNdx = 0; deviceNdx < numDevices; deviceNdx++)
+		{
+			const VkResult result = instanceDriver.createDevice(physicalDevice, &deviceCreateInfo, &devices[deviceNdx]);
+
+			if (result != VK_SUCCESS)
+			{
+				resultCollector.fail("Failed to create Device No." + de::toString(deviceNdx) + ", Error Code: " + de::toString(result));
+				break;
+			}
+
+			{
+				const DeviceDriver	deviceDriver(instanceDriver, devices[deviceNdx]);
+				VkQueue				queue;
+
+				DE_ASSERT(queueIndex < queueCount);
+				VK_CHECK(deviceDriver.getDeviceQueue(devices[deviceNdx], queueFamilyIndex, queueIndex, &queue));
+				VK_CHECK(deviceDriver.queueWaitIdle(queue));
+			}
+		}
+	}
+	catch (const vk::Error& error)
+	{
+		resultCollector.fail(de::toString(error.getError()));
+	}
+	catch (...)
+	{
+		for (int deviceNdx = (int)devices.size()-1; deviceNdx >= 0; deviceNdx--)
+		{
+			if (devices[deviceNdx] != (VkDevice)DE_NULL)
+			{
+				DeviceDriver deviceDriver(instanceDriver, devices[deviceNdx]);
+				deviceDriver.destroyDevice(devices[deviceNdx]);
+			}
+		}
+
+		throw;
+	}
+
+	for (int deviceNdx = (int)devices.size()-1; deviceNdx >= 0; deviceNdx--)
+	{
+		if (devices[deviceNdx] != (VkDevice)DE_NULL)
+		{
+			DeviceDriver deviceDriver(instanceDriver, devices[deviceNdx]);
+			deviceDriver.destroyDevice(devices[deviceNdx]);
+		}
+	}
+
+	return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
+}
+
+tcu::TestStatus createDeviceWithUnsupportedExtensionsTest (Context& context)
+{
+	tcu::TestLog&					log						= context.getTestContext().getLog();
+	const PlatformInterface&		platformInterface		= context.getPlatformInterface();
+	const Unique<VkInstance>		instance				(createDefaultInstance(platformInterface));
+	const InstanceDriver			instanceDriver			(platformInterface, instance.get());
+	const char*						enabledExtensions[]		= {"VK_UNSUPPORTED_EXTENSION", "THIS_IS_NOT_AN_EXTENSION", "VK_DONT_SUPPORT_ME"};
+	const VkPhysicalDevice			physicalDevice			= chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
+	const VkDeviceQueueCreateInfo	deviceQueueCreateInfo	=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+		DE_NULL,
+		0,										//queueFamiliIndex;
+		1,										//queueCount;
+	};
+	const VkDeviceCreateInfo		deviceCreateInfo		=
+	{
+		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,	//sType;
+		DE_NULL,								//pNext;
+		1,										//queueRecordCount;
+		&deviceQueueCreateInfo,					//pRequestedQueues;
+		0,										//layerCount;
+		DE_NULL,								//ppEnabledLayerNames;
+		DE_LENGTH_OF_ARRAY(enabledExtensions),	//extensionCount;
+		enabledExtensions,						//ppEnabledExtensionNames;
+		DE_NULL,								//pEnabledFeatures;
+	};
+
+	try
+	{
+		Unique<VkDevice> device(createDevice(instanceDriver, physicalDevice, &deviceCreateInfo));
+
+		log << TestLog::Message << "Enabled extensions are: " << TestLog::EndMessage;
+
+		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(enabledExtensions); ndx++)
+			log << TestLog::Message << enabledExtensions[ndx] <<  TestLog::EndMessage;
+
+		return tcu::TestStatus::fail("Fail, create device with unsupported extension but succeed.");
+	}
+	catch (const tcu::NotSupportedError&)
+	{
+		return tcu::TestStatus::pass("Pass, create device with unsupported extension is rejected.");
+	}
+}
+
+tcu::TestStatus createDeviceWithVariousQueueCountsTest (Context& context)
+{
+	tcu::TestLog&							log						= context.getTestContext().getLog();
+	const int								queueCountDiff			= 1;
+	const PlatformInterface&				platformInterface		= context.getPlatformInterface();
+	const Unique<VkInstance>				instance				(createDefaultInstance(platformInterface));
+	const InstanceDriver					instanceDriver			(platformInterface, instance.get());
+	const VkPhysicalDevice					physicalDevice			= chooseDevice(instanceDriver, instance.get(), context.getTestContext().getCommandLine());
+	const vector<VkQueueFamilyProperties>	queueFamilyProperties	= getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
+	vector<VkDeviceQueueCreateInfo>			deviceQueueCreateInfos;
+	VkResult								result;
+
+	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < (deUint32)queueFamilyProperties.size(); queueFamilyNdx++)
+	{
+		const deUint32 maxQueueCount = queueFamilyProperties[queueFamilyNdx].queueCount;
+
+		for (deUint32 queueCount = 1; queueCount <= maxQueueCount; queueCount += queueCountDiff)
+		{
+			const VkDeviceQueueCreateInfo queueCreateInfo =
+			{
+				VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+				DE_NULL,
+				queueFamilyNdx,
+				queueCount
+			};
+
+			deviceQueueCreateInfos.push_back(queueCreateInfo);
+		}
+	}
+
+	for (size_t testNdx = 0; testNdx < deviceQueueCreateInfos.size(); testNdx++)
+	{
+		const VkDeviceQueueCreateInfo&	queueCreateInfo		= deviceQueueCreateInfos[testNdx];
+		const VkDeviceCreateInfo		deviceCreateInfo	=
+		{
+			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,	//sType;
+			DE_NULL,								//pNext;
+			1,										//queueRecordCount;
+			&queueCreateInfo,						//pRequestedQueues;
+			0,										//layerCount;
+			DE_NULL,								//ppEnabledLayerNames;
+			0,										//extensionCount;
+			DE_NULL,								//ppEnabledExtensionNames;
+			DE_NULL,								//pEnabledFeatures;
+		};
+		const Unique<VkDevice>			device				(createDevice(instanceDriver, physicalDevice, &deviceCreateInfo));
+		const DeviceDriver				deviceDriver		(instanceDriver, device.get());
+		const deUint32					queueFamilyIndex	= deviceCreateInfo.pRequestedQueues->queueFamilyIndex;
+		const deUint32					queueCount			= deviceCreateInfo.pRequestedQueues->queueCount;
+
+		for (deUint32 queueIndex = 0; queueIndex < queueCount; queueIndex++)
+		{
+			VkQueue queue;
+			result = deviceDriver.getDeviceQueue(device.get(), queueFamilyIndex, queueIndex, &queue);
+
+			if (result != VK_SUCCESS)
+			{
+				log << TestLog::Message
+					<< "Fail to getDeviceQueue"
+					<< ", queueIndex = " << queueIndex
+					<< ", queueCreateInfo " << queueCreateInfo
+					<< ", Error Code: " << result
+					<< TestLog::EndMessage;
+				return tcu::TestStatus::fail("Fail");
+			}
+
+			result = deviceDriver.queueWaitIdle(queue);
+			if (result != VK_SUCCESS)
+			{
+				log << TestLog::Message
+					<< "vkQueueWaitIdle failed"
+					<< ",  queueIndex = " << queueIndex
+					<< ", queueCreateInfo " << queueCreateInfo
+					<< ", Error Code: " << result
+					<< TestLog::EndMessage;
+				return tcu::TestStatus::fail("Fail");
+			}
+		}
+	}
+	return tcu::TestStatus::pass("Pass");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createDeviceInitializationTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	deviceInitializationTests (new tcu::TestCaseGroup(testCtx, "device_init", "Device Initialization Tests"));
+
+	addFunctionCase(deviceInitializationTests.get(), "create_instance_name_version",			"", createInstanceTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_instance_invalid_api_version",		"", createInstanceWithInvalidApiVersionTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_instance_unsupported_extensions",	"", createInstanceWithUnsupportedExtensionsTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_device",							"", createDeviceTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_multiple_devices",					"", createMultipleDevicesTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_device_unsupported_extensions",	"", createDeviceWithUnsupportedExtensionsTest);
+	addFunctionCase(deviceInitializationTests.get(), "create_device_various_queue_counts",		"", createDeviceWithVariousQueueCountsTest);
+
+	return deviceInitializationTests.release();
+}
+
+} // api
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.hpp b/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.hpp
new file mode 100644
index 0000000..c4f459e
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiDeviceInitializationTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTAPIDEVICEINITIALIZATIONTESTS_HPP
+#define _VKTAPIDEVICEINITIALIZATIONTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Device Initialization tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+tcu::TestCaseGroup*		createDeviceInitializationTests		(tcu::TestContext& testCtx);
+
+} // api
+} // vkt
+
+#endif // _VKTAPIDEVICEINITIALIZATIONTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.cpp
new file mode 100644
index 0000000..78353e3
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.cpp
@@ -0,0 +1,2482 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Object management tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiObjectManagementTests.hpp"
+#include "vktTestCaseUtil.hpp"
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+
+#include "tcuVector.hpp"
+#include "tcuResultCollector.hpp"
+#include "tcuCommandLine.hpp"
+#include "tcuTestLog.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deSharedPtr.hpp"
+#include "deArrayUtil.hpp"
+#include "deSpinBarrier.hpp"
+#include "deThread.hpp"
+#include "deInt32.h"
+
+namespace vkt
+{
+namespace api
+{
+
+namespace
+{
+
+using namespace vk;
+
+using de::UniquePtr;
+using de::MovePtr;
+using de::SharedPtr;
+
+using tcu::IVec3;
+using tcu::UVec3;
+using tcu::ResultCollector;
+using tcu::TestStatus;
+using tcu::TestLog;
+
+using std::string;
+using std::vector;
+
+class ThreadGroupThread;
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Thread group
+ *
+ * Thread group manages collection of threads that are expected to be
+ * launched simultaneously as a group.
+ *
+ * Shared barrier is provided for synchronizing execution. Terminating thread
+ * early either by returning from ThreadGroupThread::runThread() or throwing
+ * an exception is safe, and other threads will continue execution. The
+ * thread that has been terminated is simply removed from the synchronization
+ * group.
+ *
+ * TestException-based exceptions are collected and translated into a
+ * tcu::TestStatus by using tcu::ResultCollector.
+ *
+ * Use cases for ThreadGroup include for example testing thread-safety of
+ * certain API operations by poking API simultaneously from multiple
+ * threads.
+ *//*--------------------------------------------------------------------*/
+class ThreadGroup
+{
+public:
+							ThreadGroup			(void);
+							~ThreadGroup		(void);
+
+	void					add					(de::MovePtr<ThreadGroupThread> thread);
+	TestStatus				run					(void);
+
+private:
+	typedef std::vector<de::SharedPtr<ThreadGroupThread> >	ThreadVector;
+
+	ThreadVector			m_threads;
+	de::SpinBarrier			m_barrier;
+} DE_WARN_UNUSED_TYPE;
+
+class ThreadGroupThread : private de::Thread
+{
+public:
+							ThreadGroupThread	(void);
+	virtual					~ThreadGroupThread	(void);
+
+	void					start				(de::SpinBarrier* groupBarrier);
+
+	ResultCollector&		getResultCollector	(void) { return m_resultCollector; }
+
+	using de::Thread::join;
+
+protected:
+	virtual void			runThread			(void) = 0;
+
+	void					barrier				(void);
+
+private:
+							ThreadGroupThread	(const ThreadGroupThread&);
+	ThreadGroupThread&		operator=			(const ThreadGroupThread&);
+
+	void					run					(void);
+
+	ResultCollector			m_resultCollector;
+	de::SpinBarrier*		m_barrier;
+};
+
+// ThreadGroup
+
+ThreadGroup::ThreadGroup (void)
+	: m_barrier(1)
+{
+}
+
+ThreadGroup::~ThreadGroup (void)
+{
+}
+
+void ThreadGroup::add (de::MovePtr<ThreadGroupThread> thread)
+{
+	m_threads.push_back(de::SharedPtr<ThreadGroupThread>(thread.release()));
+}
+
+tcu::TestStatus ThreadGroup::run (void)
+{
+	tcu::ResultCollector	resultCollector;
+
+	m_barrier.reset((int)m_threads.size());
+
+	for (ThreadVector::iterator threadIter = m_threads.begin(); threadIter != m_threads.end(); ++threadIter)
+		(*threadIter)->start(&m_barrier);
+
+	for (ThreadVector::iterator threadIter = m_threads.begin(); threadIter != m_threads.end(); ++threadIter)
+	{
+		tcu::ResultCollector&	threadResult	= (*threadIter)->getResultCollector();
+		(*threadIter)->join();
+		resultCollector.addResult(threadResult.getResult(), threadResult.getMessage());
+	}
+
+	return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
+}
+
+// ThreadGroupThread
+
+ThreadGroupThread::ThreadGroupThread (void)
+	: m_barrier(DE_NULL)
+{
+}
+
+ThreadGroupThread::~ThreadGroupThread (void)
+{
+}
+
+void ThreadGroupThread::start (de::SpinBarrier* groupBarrier)
+{
+	m_barrier = groupBarrier;
+	de::Thread::start();
+}
+
+void ThreadGroupThread::run (void)
+{
+	try
+	{
+		runThread();
+	}
+	catch (const tcu::TestException& e)
+	{
+		getResultCollector().addResult(e.getTestResult(), e.getMessage());
+	}
+	catch (const std::exception& e)
+	{
+		getResultCollector().addResult(QP_TEST_RESULT_FAIL, e.what());
+	}
+	catch (...)
+	{
+		getResultCollector().addResult(QP_TEST_RESULT_FAIL, "Exception");
+	}
+
+	m_barrier->removeThread(de::SpinBarrier::WAIT_MODE_AUTO);
+}
+
+inline void ThreadGroupThread::barrier (void)
+{
+	m_barrier->sync(de::SpinBarrier::WAIT_MODE_AUTO);
+}
+
+deUint32 getDefaultTestThreadCount (void)
+{
+	return de::clamp(deGetNumAvailableLogicalCores(), 2u, 8u);
+}
+
+// Utilities
+
+struct Environment
+{
+	const PlatformInterface&	vkp;
+	const DeviceInterface&		vkd;
+	VkDevice					device;
+	deUint32					queueFamilyIndex;
+	const BinaryCollection&		programBinaries;
+	deUint32					maxResourceConsumers;		// Maximum number of objects using same Object::Resources concurrently
+
+	Environment (Context& context, deUint32 maxResourceConsumers_)
+		: vkp					(context.getPlatformInterface())
+		, vkd					(context.getDeviceInterface())
+		, device				(context.getDevice())
+		, queueFamilyIndex		(context.getUniversalQueueFamilyIndex())
+		, programBinaries		(context.getBinaryCollection())
+		, maxResourceConsumers	(maxResourceConsumers_)
+	{
+	}
+
+	Environment (const PlatformInterface&	vkp_,
+				 const DeviceInterface&		vkd_,
+				 VkDevice					device_,
+				 deUint32					queueFamilyIndex_,
+				 const BinaryCollection&	programBinaries_,
+				 deUint32					maxResourceConsumers_)
+		: vkp					(vkp_)
+		, vkd					(vkd_)
+		, device				(device_)
+		, queueFamilyIndex		(queueFamilyIndex_)
+		, programBinaries		(programBinaries_)
+		, maxResourceConsumers	(maxResourceConsumers_)
+	{
+	}
+};
+
+template<typename Case>
+struct Dependency
+{
+	typename Case::Resources		resources;
+	Unique<typename Case::Type>		object;
+
+	Dependency (const Environment& env, const typename Case::Parameters& params)
+		: resources	(env, params)
+		, object	(Case::create(env, resources, params))
+	{}
+};
+
+// Object definitions
+
+enum
+{
+	DEFAULT_MAX_CONCURRENT_OBJECTS	= 16*1024
+};
+
+struct Instance
+{
+	typedef VkInstance Type;
+
+	enum { MAX_CONCURRENT = 32 };
+
+	struct Parameters
+	{
+		Parameters (void) {}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkInstance> create (const Environment& env, const Resources&, const Parameters&)
+	{
+		const VkApplicationInfo		appInfo			=
+		{
+			VK_STRUCTURE_TYPE_APPLICATION_INFO,
+			DE_NULL,
+			DE_NULL,							// pAppName
+			0u,									// appVersion
+			DE_NULL,							// pEngineName
+			0u,									// engineVersion
+			VK_API_VERSION
+		};
+		const VkInstanceCreateInfo	instanceInfo	=
+		{
+			VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+			DE_NULL,
+			&appInfo,
+			DE_NULL,							// pAllocCb
+			0u,									// layerCount
+			DE_NULL,							// ppEnabledLayerNames
+			0u,									// extensionCount
+			DE_NULL,							// ppEnabledExtensionNames
+		};
+
+		return createInstance(env.vkp, &instanceInfo);
+	}
+};
+
+struct Device
+{
+	typedef VkDevice Type;
+
+	enum { MAX_CONCURRENT = 32 };
+
+	struct Parameters
+	{
+		deUint32		deviceIndex;
+		VkQueueFlags	queueFlags;
+
+		Parameters (deUint32 deviceIndex_, VkQueueFlags queueFlags_)
+			: deviceIndex	(deviceIndex_)
+			, queueFlags	(queueFlags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<Instance>	instance;
+		InstanceDriver			vki;
+		VkPhysicalDevice		physicalDevice;
+		deUint32				queueFamilyIndex;
+
+		Resources (const Environment& env, const Parameters& params)
+			: instance			(env, Instance::Parameters())
+			, vki				(env.vkp, *instance.object)
+			, physicalDevice	(0)
+			, queueFamilyIndex	(~0u)
+		{
+			{
+				const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(vki, *instance.object);
+
+				if (physicalDevices.size() <= (size_t)params.deviceIndex)
+					TCU_THROW(NotSupportedError, "Device not found");
+
+				physicalDevice = physicalDevices[params.deviceIndex];
+			}
+
+			{
+				const vector<VkQueueFamilyProperties>	queueProps		= getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice);
+				bool									foundMatching	= false;
+
+				for (size_t curQueueNdx = 0; curQueueNdx < queueProps.size(); curQueueNdx++)
+				{
+					if ((queueProps[curQueueNdx].queueFlags & params.queueFlags) == params.queueFlags)
+					{
+						queueFamilyIndex	= (deUint32)curQueueNdx;
+						foundMatching		= true;
+					}
+				}
+
+				if (!foundMatching)
+					TCU_THROW(NotSupportedError, "Matching queue not found");
+			}
+		}
+	};
+
+	static Move<VkDevice> create (const Environment&, const Resources& res, const Parameters&)
+	{
+		const VkDeviceQueueCreateInfo	queues[]	=
+		{
+			{
+				VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+				DE_NULL,
+				res.queueFamilyIndex,
+				1u,									// queueCount
+			}
+		};
+		const VkDeviceCreateInfo	deviceInfo	=
+		{
+			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+			DE_NULL,
+			DE_LENGTH_OF_ARRAY(queues),
+			queues,
+			0u,										// layerCount
+			DE_NULL,								// ppEnabledLayerNames
+			0u,										// extensionCount
+			DE_NULL,								// ppEnabledExtensionNames
+			DE_NULL,								// pEnabledFeatures
+		};
+
+		return createDevice(res.vki, res.physicalDevice, &deviceInfo);
+	}
+};
+
+struct DeviceMemory
+{
+	typedef VkDeviceMemory Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkDeviceSize	size;
+		deUint32		memoryTypeIndex;
+
+		Parameters (VkDeviceSize size_, deUint32 memoryTypeIndex_)
+			: size				(size_)
+			, memoryTypeIndex	(memoryTypeIndex_)
+		{
+			DE_ASSERT(memoryTypeIndex < VK_MAX_MEMORY_TYPES);
+		}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkDeviceMemory> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkMemoryAllocInfo	allocInfo	=
+		{
+			VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
+			DE_NULL,
+			params.size,
+			params.memoryTypeIndex
+		};
+
+		return allocMemory(env.vkd, env.device, &allocInfo);
+	}
+};
+
+DeviceMemory::Parameters getDeviceMemoryParameters (const VkMemoryRequirements& memReqs)
+{
+	return DeviceMemory::Parameters(memReqs.size, deCtz32(memReqs.memoryTypeBits));
+}
+
+DeviceMemory::Parameters getDeviceMemoryParameters (const Environment& env, VkImage image)
+{
+	return getDeviceMemoryParameters(getImageMemoryRequirements(env.vkd, env.device, image));
+}
+
+DeviceMemory::Parameters getDeviceMemoryParameters (const Environment& env, VkBuffer image)
+{
+	return getDeviceMemoryParameters(getBufferMemoryRequirements(env.vkd, env.device, image));
+}
+
+struct Buffer
+{
+	typedef VkBuffer Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkDeviceSize		size;
+		VkBufferUsageFlags	usage;
+
+		Parameters (VkDeviceSize		size_,
+					VkBufferUsageFlags	usage_)
+			: size	(size_)
+			, usage	(usage_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkBuffer> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkBufferCreateInfo	bufferInfo	=
+		{
+			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+			DE_NULL,
+			params.size,
+			params.usage,
+			0u,										// flags
+			VK_SHARING_MODE_EXCLUSIVE,
+			1u,
+			&env.queueFamilyIndex
+		};
+
+		return createBuffer(env.vkd, env.device, &bufferInfo);
+	}
+};
+
+struct BufferView
+{
+	typedef VkBufferView Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		Buffer::Parameters	buffer;
+		VkFormat			format;
+		VkDeviceSize		offset;
+		VkDeviceSize		range;
+
+		Parameters (const Buffer::Parameters&	buffer_,
+					VkFormat					format_,
+					VkDeviceSize				offset_,
+					VkDeviceSize				range_)
+			: buffer	(buffer_)
+			, format	(format_)
+			, offset	(offset_)
+			, range		(range_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<Buffer>			buffer;
+		Dependency<DeviceMemory>	memory;
+
+		Resources (const Environment& env, const Parameters& params)
+			: buffer(env, params.buffer)
+			, memory(env, getDeviceMemoryParameters(env, *buffer.object))
+		{
+			VK_CHECK(env.vkd.bindBufferMemory(env.device, *buffer.object, *memory.object, 0));
+		}
+	};
+
+	static Move<VkBufferView> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		const VkBufferViewCreateInfo	bufferViewInfo	=
+		{
+			VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
+			DE_NULL,
+			*res.buffer.object,
+			params.format,
+			params.offset,
+			params.range
+		};
+
+		return createBufferView(env.vkd, env.device, &bufferViewInfo);
+	}
+};
+
+struct Image
+{
+	typedef VkImage Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkImageType			imageType;
+		VkFormat			format;
+		VkExtent3D			extent;
+		deUint32			mipLevels;
+		deUint32			arraySize;
+		deUint32			samples;
+		VkImageTiling		tiling;
+		VkImageUsageFlags	usage;
+		VkImageLayout		initialLayout;
+
+		Parameters (VkImageType			imageType_,
+					VkFormat			format_,
+					VkExtent3D			extent_,
+					deUint32			mipLevels_,
+					deUint32			arraySize_,
+					deUint32			samples_,
+					VkImageTiling		tiling_,
+					VkImageUsageFlags	usage_,
+					VkImageLayout		initialLayout_)
+			: imageType		(imageType_)
+			, format		(format_)
+			, extent		(extent_)
+			, mipLevels		(mipLevels_)
+			, arraySize		(arraySize_)
+			, samples		(samples_)
+			, tiling		(tiling_)
+			, usage			(usage_)
+			, initialLayout	(initialLayout_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkImage> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkImageCreateInfo		imageInfo	=
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+			DE_NULL,
+			params.imageType,
+			params.format,
+			params.extent,
+			params.mipLevels,
+			params.arraySize,
+			params.samples,
+			params.tiling,
+			params.usage,
+			0u,								// flags
+			VK_SHARING_MODE_EXCLUSIVE,		// sharingMode
+			1u,								// queueFamilyCount
+			&env.queueFamilyIndex,			// pQueueFamilyIndices
+			params.initialLayout
+		};
+
+		return createImage(env.vkd, env.device, &imageInfo);
+	}
+};
+
+struct ImageView
+{
+	typedef VkImageView Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		Image::Parameters		image;
+		VkImageViewType			viewType;
+		VkFormat				format;
+		VkChannelMapping		channels;
+		VkImageSubresourceRange	subresourceRange;
+
+		Parameters (const Image::Parameters&	image_,
+					VkImageViewType				viewType_,
+					VkFormat					format_,
+					VkChannelMapping			channels_,
+					VkImageSubresourceRange		subresourceRange_)
+			: image				(image_)
+			, viewType			(viewType_)
+			, format			(format_)
+			, channels			(channels_)
+			, subresourceRange	(subresourceRange_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<Image>			image;
+		Dependency<DeviceMemory>	memory;
+
+		Resources (const Environment& env, const Parameters& params)
+			: image	(env, params.image)
+			, memory(env, getDeviceMemoryParameters(env, *image.object))
+		{
+			VK_CHECK(env.vkd.bindImageMemory(env.device, *image.object, *memory.object, 0));
+		}
+	};
+
+	static Move<VkImageView> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		const VkImageViewCreateInfo	imageViewInfo	=
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+			DE_NULL,
+			*res.image.object,
+			params.viewType,
+			params.format,
+			params.channels,
+			params.subresourceRange,
+			0u,							// flags
+		};
+
+		return createImageView(env.vkd, env.device, &imageViewInfo);
+	}
+};
+
+struct Semaphore
+{
+	typedef VkSemaphore Type;
+
+	enum { MAX_CONCURRENT = 100 };
+
+	struct Parameters
+	{
+		VkSemaphoreCreateFlags	flags;
+
+		Parameters (VkSemaphoreCreateFlags flags_)
+			: flags(flags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkSemaphore> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkSemaphoreCreateInfo	semaphoreInfo	=
+		{
+			VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+			DE_NULL,
+			params.flags
+		};
+
+		return createSemaphore(env.vkd, env.device, &semaphoreInfo);
+	}
+};
+
+struct Fence
+{
+	typedef VkFence Type;
+
+	enum { MAX_CONCURRENT = 100 };
+
+	struct Parameters
+	{
+		VkFenceCreateFlags	flags;
+
+		Parameters (VkFenceCreateFlags flags_)
+			: flags(flags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkFence> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkFenceCreateInfo	fenceInfo	=
+		{
+			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+			DE_NULL,
+			params.flags
+		};
+
+		return createFence(env.vkd, env.device, &fenceInfo);
+	}
+};
+
+struct Event
+{
+	typedef VkEvent Type;
+
+	enum { MAX_CONCURRENT = 100 };
+
+	struct Parameters
+	{
+		VkEventCreateFlags	flags;
+
+		Parameters (VkEventCreateFlags flags_)
+			: flags(flags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkEvent> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkEventCreateInfo	eventInfo	=
+		{
+			VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
+			DE_NULL,
+			params.flags
+		};
+
+		return createEvent(env.vkd, env.device, &eventInfo);
+	}
+};
+
+struct QueryPool
+{
+	typedef VkQueryPool Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkQueryType						queryType;
+		deUint32						slots;
+		VkQueryPipelineStatisticFlags	pipelineStatistics;
+
+		Parameters (VkQueryType						queryType_,
+					deUint32						slots_,
+					VkQueryPipelineStatisticFlags	pipelineStatistics_)
+			: queryType				(queryType_)
+			, slots					(slots_)
+			, pipelineStatistics	(pipelineStatistics_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkQueryPool> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkQueryPoolCreateInfo	queryPoolInfo	=
+		{
+			VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
+			DE_NULL,
+			params.queryType,
+			params.slots,
+			params.pipelineStatistics
+		};
+
+		return createQueryPool(env.vkd, env.device, &queryPoolInfo);
+	}
+};
+
+struct ShaderModule
+{
+	typedef VkShaderModule Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		string		binaryName;
+
+		Parameters (const std::string& binaryName_)
+			: binaryName(binaryName_)
+		{}
+	};
+
+	struct Resources
+	{
+		const ProgramBinary&	binary;
+
+		Resources (const Environment& env, const Parameters& params)
+			: binary(env.programBinaries.get(params.binaryName))
+		{}
+	};
+
+	static void initPrograms (SourceCollections& dst, Parameters params)
+	{
+		dst.glslSources.add(params.binaryName)
+			<< glu::VertexSource(
+				"#version 310 es\n"
+				"layout(location = 0) in highp vec4 a_position;\n"
+				"void main () { gl_Position = a_position; }\n");
+	}
+
+	static Move<VkShaderModule> create (const Environment& env, const Resources& res, const Parameters&)
+	{
+		const VkShaderModuleCreateInfo	shaderModuleInfo	=
+		{
+			VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+			DE_NULL,
+			res.binary.getSize(),
+			res.binary.getBinary(),
+			0u,												// flags
+		};
+
+		return createShaderModule(env.vkd, env.device, &shaderModuleInfo);
+	}
+};
+
+struct Shader
+{
+	typedef VkShader Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		ShaderModule::Parameters	shaderModule;
+		VkShaderStage				stage;
+
+		Parameters (const ShaderModule::Parameters&	shaderModule_,
+					VkShaderStage					stage_)
+			: shaderModule	(shaderModule_)
+			, stage			(stage_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<ShaderModule>	shaderModule;
+
+		Resources (const Environment& env, const Parameters& params)
+			: shaderModule(env, params.shaderModule)
+		{}
+	};
+
+	static void initPrograms (SourceCollections& dst, Parameters params)
+	{
+		static const char*	s_sources[] =
+		{
+			// VK_SHADER_STAGE_VERTEX
+			"#version 310 es\n"
+			"layout(location = 0) in highp vec4 a_position;\n"
+			"void main () { gl_Position = a_position; }\n",
+
+			// VK_SHADER_STAGE_TESS_CONTROL
+			DE_NULL,
+
+			// VK_SHADER_STAGE_TESS_EVALUATION
+			DE_NULL,
+
+			// VK_SHADER_STAGE_GEOMETRY
+			DE_NULL,
+
+			// VK_SHADER_STAGE_FRAGMENT
+			"#version 310 es\n"
+			"layout(location = 0) out mediump vec4 o_color;\n"
+			"void main () { o_color = vec4(1.0, 0.5, 0.25, 1.0); }",
+
+			// VK_SHADER_STAGE_COMPUTE
+			"#version 310 es\n"
+			"layout(binding = 0) buffer Input { highp uint dataIn[]; };\n"
+			"layout(binding = 1) buffer Output { highp uint dataOut[]; };\n"
+			"void main (void)\n"
+			"{\n"
+			"	dataOut[gl_GlobalInvocationID.x] = ~dataIn[gl_GlobalInvocationID.x];\n"
+			"}\n"
+		};
+		const char* const	source	= de::getSizedArrayElement<VK_SHADER_STAGE_COMPUTE+1>(s_sources, params.stage);
+
+		DE_ASSERT(source);
+
+		dst.glslSources.add(params.shaderModule.binaryName)
+			<< glu::ShaderSource(getGluShaderType(params.stage), source);
+	}
+
+	static Move<VkShader> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		const VkShaderCreateInfo	shaderInfo	=
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,
+			DE_NULL,
+			*res.shaderModule.object,
+			"main",										// pName
+			0u,											// flags
+			params.stage
+		};
+
+		return createShader(env.vkd, env.device, &shaderInfo);
+	}
+};
+
+struct PipelineCache
+{
+	typedef VkPipelineCache Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		deUintptr	maxSize;
+
+		Parameters (deUintptr	maxSize_)
+			: maxSize	(maxSize_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkPipelineCache> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkPipelineCacheCreateInfo	pipelineCacheInfo	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+			DE_NULL,
+			0u,					// initialSize
+			DE_NULL,			// initialData
+			params.maxSize
+		};
+
+		return createPipelineCache(env.vkd, env.device, &pipelineCacheInfo);
+	}
+};
+
+struct Sampler
+{
+	typedef VkSampler Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkTexFilter			magFilter;
+		VkTexFilter			minFilter;
+		VkTexMipmapMode		mipMode;
+		VkTexAddressMode	addressU;
+		VkTexAddressMode	addressV;
+		VkTexAddressMode	addressW;
+		float				mipLodBias;
+		float				maxAnisotropy;
+		VkBool32			compareEnable;
+		VkCompareOp			compareOp;
+		float				minLod;
+		float				maxLod;
+		VkBorderColor		borderColor;
+		VkBool32			unnormalizedCoordinates;
+
+		// \todo [2015-09-17 pyry] Other configurations
+		Parameters (void)
+			: magFilter					(VK_TEX_FILTER_NEAREST)
+			, minFilter					(VK_TEX_FILTER_NEAREST)
+			, mipMode					(VK_TEX_MIPMAP_MODE_BASE)
+			, addressU					(VK_TEX_ADDRESS_MODE_CLAMP)
+			, addressV					(VK_TEX_ADDRESS_MODE_CLAMP)
+			, addressW					(VK_TEX_ADDRESS_MODE_CLAMP)
+			, mipLodBias				(0.0f)
+			, maxAnisotropy				(0.0f)
+			, compareEnable				(VK_FALSE)
+			, compareOp					(VK_COMPARE_OP_ALWAYS)
+			, minLod					(-1000.f)
+			, maxLod					(+1000.f)
+			, borderColor				(VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK)
+			, unnormalizedCoordinates	(VK_FALSE)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkSampler> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkSamplerCreateInfo	samplerInfo	=
+		{
+			VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+			DE_NULL,
+			params.magFilter,
+			params.minFilter,
+			params.mipMode,
+			params.addressU,
+			params.addressV,
+			params.addressW,
+			params.mipLodBias,
+			params.maxAnisotropy,
+			params.compareEnable,
+			params.compareOp,
+			params.minLod,
+			params.maxLod,
+			params.borderColor,
+			params.unnormalizedCoordinates
+		};
+
+		return createSampler(env.vkd, env.device, &samplerInfo);
+	}
+};
+
+struct DescriptorSetLayout
+{
+	typedef VkDescriptorSetLayout Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		struct Binding
+		{
+			VkDescriptorType	type;
+			deUint32			arraySize;
+			VkShaderStageFlags	stageFlags;
+			bool				useImmutableSampler;
+
+			Binding (VkDescriptorType	type_,
+					 deUint32			arraySize_,
+					 VkShaderStageFlags	stageFlags_,
+					 bool				useImmutableSampler_)
+				: type					(type_)
+				, arraySize				(arraySize_)
+				, stageFlags			(stageFlags_)
+				, useImmutableSampler	(useImmutableSampler_)
+			{}
+
+			Binding (void) {}
+		};
+
+		vector<Binding>	bindings;
+
+		Parameters (const vector<Binding>& bindings_)
+			: bindings(bindings_)
+		{}
+
+		static Parameters empty (void)
+		{
+			return Parameters(vector<Binding>());
+		}
+
+		static Parameters single (VkDescriptorType		type,
+								  deUint32				arraySize,
+								  VkShaderStageFlags	stageFlags,
+								  bool					useImmutableSampler = false)
+		{
+			vector<Binding> bindings;
+			bindings.push_back(Binding(type, arraySize, stageFlags, useImmutableSampler));
+			return Parameters(bindings);
+		}
+	};
+
+	struct Resources
+	{
+		vector<VkDescriptorSetLayoutBinding>	bindings;
+		MovePtr<Dependency<Sampler> >			immutableSampler;
+		vector<VkSampler>						immutableSamplersPtr;
+
+		Resources (const Environment& env, const Parameters& params)
+		{
+			// Create immutable sampler if needed
+			for (vector<Parameters::Binding>::const_iterator cur = params.bindings.begin(); cur != params.bindings.end(); cur++)
+			{
+				if (cur->useImmutableSampler && !immutableSampler)
+				{
+					immutableSampler = de::newMovePtr<Dependency<Sampler> >(env, Sampler::Parameters());
+
+					if (cur->useImmutableSampler && immutableSamplersPtr.size() < (size_t)cur->arraySize)
+						immutableSamplersPtr.resize(cur->arraySize, *immutableSampler->object);
+				}
+			}
+
+			for (vector<Parameters::Binding>::const_iterator cur = params.bindings.begin(); cur != params.bindings.end(); cur++)
+			{
+				const VkDescriptorSetLayoutBinding	binding	=
+				{
+					cur->type,
+					cur->arraySize,
+					cur->stageFlags,
+					(cur->useImmutableSampler ? &immutableSamplersPtr[0] : DE_NULL)
+				};
+
+				bindings.push_back(binding);
+			}
+		}
+	};
+
+	static Move<VkDescriptorSetLayout> create (const Environment& env, const Resources& res, const Parameters&)
+	{
+		const VkDescriptorSetLayoutCreateInfo	descriptorSetLayoutInfo	=
+		{
+			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+			DE_NULL,
+			(deUint32)res.bindings.size(),
+			(res.bindings.empty() ? DE_NULL : &res.bindings[0])
+		};
+
+		return createDescriptorSetLayout(env.vkd, env.device, &descriptorSetLayoutInfo);
+	}
+};
+
+struct PipelineLayout
+{
+	typedef VkPipelineLayout Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		vector<DescriptorSetLayout::Parameters>	descriptorSetLayouts;
+		vector<VkPushConstantRange>				pushConstantRanges;
+
+		Parameters (void) {}
+
+		static Parameters empty (void)
+		{
+			return Parameters();
+		}
+
+		static Parameters singleDescriptorSet (const DescriptorSetLayout::Parameters& descriptorSetLayout)
+		{
+			Parameters params;
+			params.descriptorSetLayouts.push_back(descriptorSetLayout);
+			return params;
+		}
+	};
+
+	struct Resources
+	{
+		typedef SharedPtr<Dependency<DescriptorSetLayout> >	DescriptorSetLayoutDepSp;
+		typedef vector<DescriptorSetLayoutDepSp>			DescriptorSetLayouts;
+
+		DescriptorSetLayouts			descriptorSetLayouts;
+		vector<VkDescriptorSetLayout>	pSetLayouts;
+
+		Resources (const Environment& env, const Parameters& params)
+		{
+			for (vector<DescriptorSetLayout::Parameters>::const_iterator dsParams = params.descriptorSetLayouts.begin();
+				 dsParams != params.descriptorSetLayouts.end();
+				 ++dsParams)
+			{
+				descriptorSetLayouts.push_back(DescriptorSetLayoutDepSp(new Dependency<DescriptorSetLayout>(env, *dsParams)));
+				pSetLayouts.push_back(*descriptorSetLayouts.back()->object);
+			}
+		}
+	};
+
+	static Move<VkPipelineLayout> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		const VkPipelineLayoutCreateInfo	pipelineLayoutInfo	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+			DE_NULL,
+			(deUint32)res.pSetLayouts.size(),
+			(res.pSetLayouts.empty() ? DE_NULL : &res.pSetLayouts[0]),
+			(deUint32)params.pushConstantRanges.size(),
+			(params.pushConstantRanges.empty() ? DE_NULL : &params.pushConstantRanges[0]),
+		};
+
+		return createPipelineLayout(env.vkd, env.device, &pipelineLayoutInfo);
+	}
+};
+
+struct RenderPass
+{
+	typedef VkRenderPass Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	// \todo [2015-09-17 pyry] More interesting configurations
+	struct Parameters
+	{
+		Parameters (void) {}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkRenderPass> create (const Environment& env, const Resources&, const Parameters&)
+	{
+		const VkAttachmentDescription	attachments[]		=
+		{
+			{
+				VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,
+				DE_NULL,
+				VK_FORMAT_R8G8B8A8_UNORM,
+				1u,
+				VK_ATTACHMENT_LOAD_OP_CLEAR,
+				VK_ATTACHMENT_STORE_OP_STORE,
+				VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+				VK_ATTACHMENT_STORE_OP_DONT_CARE,
+				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+				0u											// flags
+			},
+			{
+				VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,
+				DE_NULL,
+				VK_FORMAT_D16_UNORM,
+				1u,
+				VK_ATTACHMENT_LOAD_OP_CLEAR,
+				VK_ATTACHMENT_STORE_OP_DONT_CARE,
+				VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+				VK_ATTACHMENT_STORE_OP_DONT_CARE,
+				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+				0u											// flags
+			}
+		};
+		const VkAttachmentReference		colorAttachments[]	=
+		{
+			{
+				0u,											// attachment
+				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+			}
+		};
+		const VkSubpassDescription		subpasses[]			=
+		{
+			{
+				VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,
+				DE_NULL,
+				VK_PIPELINE_BIND_POINT_GRAPHICS,
+				0u,											// flags
+				0u,											// inputCount
+				DE_NULL,									// pInputAttachments
+				DE_LENGTH_OF_ARRAY(colorAttachments),
+				colorAttachments,
+				DE_NULL,									// pResolveAttachments
+				{
+					1u,											// attachment
+					VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+				},
+				0u,											// preserveCount
+				DE_NULL,									// pPreserveAttachments
+			}
+		};
+		const VkRenderPassCreateInfo	renderPassInfo		=
+		{
+			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+			DE_NULL,
+			DE_LENGTH_OF_ARRAY(attachments),
+			attachments,
+			DE_LENGTH_OF_ARRAY(subpasses),
+			subpasses,
+			0u,												// dependencyCount
+			DE_NULL											// pDependencies
+		};
+
+		return createRenderPass(env.vkd, env.device, &renderPassInfo);
+	}
+};
+
+struct GraphicsPipeline
+{
+	typedef VkPipeline Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	// \todo [2015-09-17 pyry] More interesting configurations
+	struct Parameters
+	{
+		Parameters (void) {}
+	};
+
+	struct Resources
+	{
+		Dependency<Shader>			vertexShader;
+		Dependency<Shader>			fragmentShader;
+		Dependency<PipelineLayout>	layout;
+		Dependency<RenderPass>		renderPass;
+		Dependency<PipelineCache>	pipelineCache;
+
+		Resources (const Environment& env, const Parameters&)
+			: vertexShader		(env, Shader::Parameters(ShaderModule::Parameters("vert"), VK_SHADER_STAGE_VERTEX))
+			, fragmentShader	(env, Shader::Parameters(ShaderModule::Parameters("frag"), VK_SHADER_STAGE_FRAGMENT))
+			, layout			(env, PipelineLayout::Parameters::singleDescriptorSet(
+										DescriptorSetLayout::Parameters::single(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, VK_SHADER_STAGE_FRAGMENT_BIT, true)))
+			, renderPass		(env, RenderPass::Parameters())
+			, pipelineCache		(env, PipelineCache::Parameters(1024u*1024u))
+		{}
+	};
+
+	static void initPrograms (SourceCollections& dst, Parameters)
+	{
+		Shader::initPrograms(dst, Shader::Parameters(ShaderModule::Parameters("vert"), VK_SHADER_STAGE_VERTEX));
+		Shader::initPrograms(dst, Shader::Parameters(ShaderModule::Parameters("frag"), VK_SHADER_STAGE_FRAGMENT));
+	}
+
+	static Move<VkPipeline> create (const Environment& env, const Resources& res, const Parameters&)
+	{
+		const VkPipelineShaderStageCreateInfo			stages[]			=
+		{
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+				DE_NULL,
+				VK_SHADER_STAGE_VERTEX,
+				*res.vertexShader.object,
+				DE_NULL
+			},
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+				DE_NULL,
+				VK_SHADER_STAGE_FRAGMENT,
+				*res.fragmentShader.object,
+				DE_NULL
+			}
+		};
+		const VkVertexInputBindingDescription			vertexBindings[]	=
+		{
+			{
+				0u,									// binding
+				16u,								// strideInBytes
+				VK_VERTEX_INPUT_STEP_RATE_VERTEX
+			}
+		};
+		const VkVertexInputAttributeDescription			vertexAttribs[]		=
+		{
+			{
+				0u,									// location
+				0u,									// binding
+				VK_FORMAT_R32G32B32A32_SFLOAT,
+				0u,									// offsetInBytes
+			}
+		};
+		const VkPipelineVertexInputStateCreateInfo		vertexInputState	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+			DE_NULL,
+			DE_LENGTH_OF_ARRAY(vertexBindings),
+			vertexBindings,
+			DE_LENGTH_OF_ARRAY(vertexAttribs),
+			vertexAttribs
+		};
+		const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyState	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+			DE_NULL,
+			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+			VK_FALSE								// primitiveRestartEnable
+		};
+		const VkViewport								viewports[]			=
+		{
+			{ 0.0f, 0.0f, 64.f, 64.f, 0.0f, 1.0f }
+		};
+		const VkRect2D									scissors[]			=
+		{
+			{ { 0, 0 }, { 64, 64 } }
+		};
+		const VkPipelineViewportStateCreateInfo			viewportState		=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+			DE_NULL,
+			DE_LENGTH_OF_ARRAY(viewports),
+			viewports,
+			DE_LENGTH_OF_ARRAY(scissors),
+			scissors,
+		};
+		const VkPipelineRasterStateCreateInfo			rasterState			=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,
+			DE_NULL,
+			VK_TRUE,								// depthClipEnable
+			VK_FALSE,								// rasterizerDiscardEnable
+			VK_FILL_MODE_SOLID,
+			VK_CULL_MODE_BACK,
+			VK_FRONT_FACE_CCW,
+			VK_FALSE,								// depthBiasEnable
+			0.0f,									// depthBias
+			0.0f,									// depthBiasClamp
+			0.0f,									// slopeScaledDepthBias
+			1.0f,									// lineWidth
+		};
+		const VkPipelineMultisampleStateCreateInfo		multisampleState	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+			DE_NULL,
+			1u,										// rasterSamples
+			VK_FALSE,								// sampleShadingEnable
+			1.0f,									// minSampleShading
+			DE_NULL,								// pSampleMask
+		};
+		const VkPipelineDepthStencilStateCreateInfo		depthStencilState	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+			DE_NULL,
+			VK_TRUE,								// depthTestEnable
+			VK_TRUE,								// depthWriteEnable
+			VK_COMPARE_OP_LESS,						// depthCompareOp
+			VK_TRUE,								// depthBoundsTestEnable
+			VK_FALSE,								// stencilTestEnable
+			{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },
+			{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },
+			-1.0f,									// minDepthBounds
+			+1.0f,									// maxDepthBounds
+		};
+		const VkPipelineColorBlendAttachmentState		colorBlendAttState[]=
+		{
+			{
+				VK_FALSE,							// blendEnable
+				VK_BLEND_ONE,
+				VK_BLEND_ZERO,
+				VK_BLEND_OP_ADD,
+				VK_BLEND_ONE,
+				VK_BLEND_ZERO,
+				VK_BLEND_OP_ADD,
+				VK_CHANNEL_R_BIT|VK_CHANNEL_G_BIT|VK_CHANNEL_B_BIT|VK_CHANNEL_A_BIT
+			}
+		};
+		const VkPipelineColorBlendStateCreateInfo		colorBlendState		=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+			DE_NULL,
+			VK_FALSE,								// alphaToCoverageEnable
+			VK_FALSE,								// alphaToOneEnable
+			VK_FALSE,								// logicOpEnable
+			VK_LOGIC_OP_COPY,
+			DE_LENGTH_OF_ARRAY(colorBlendAttState),
+			colorBlendAttState,
+			{ 0.0f, 0.0f, 0.0f, 0.0f }				// blendConst
+		};
+		const VkPipelineDynamicStateCreateInfo			dynamicState		=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+			DE_NULL,
+			0u,										// dynamicStateCount
+			DE_NULL,								// pDynamicStates
+		};
+		const VkGraphicsPipelineCreateInfo				pipelineInfo		=
+		{
+			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+			DE_NULL,
+			DE_LENGTH_OF_ARRAY(stages),
+			stages,
+			&vertexInputState,
+			&inputAssemblyState,
+			DE_NULL,								// pTessellationState
+			&viewportState,
+			&rasterState,
+			&multisampleState,
+			&depthStencilState,
+			&colorBlendState,
+			&dynamicState,
+			0u,										// flags
+			*res.layout.object,
+			*res.renderPass.object,
+			0u,										// subpass
+			(VkPipeline)0,							// basePipelineHandle
+			0,										// basePipelineIndex
+		};
+
+		return createGraphicsPipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+	}
+};
+
+struct ComputePipeline
+{
+	typedef VkPipeline Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	// \todo [2015-09-17 pyry] More interesting configurations
+	struct Parameters
+	{
+		Parameters (void) {}
+	};
+
+	struct Resources
+	{
+		Dependency<Shader>			shader;
+		Dependency<PipelineLayout>	layout;
+		Dependency<PipelineCache>	pipelineCache;
+
+		static DescriptorSetLayout::Parameters getDescriptorSetLayout (void)
+		{
+			typedef DescriptorSetLayout::Parameters::Binding Binding;
+
+			vector<Binding> bindings;
+
+			bindings.push_back(Binding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_COMPUTE, false));
+			bindings.push_back(Binding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, VK_SHADER_STAGE_COMPUTE, false));
+
+			return DescriptorSetLayout::Parameters(bindings);
+		}
+
+		Resources (const Environment& env, const Parameters&)
+			: shader			(env, Shader::Parameters(ShaderModule::Parameters("comp"), VK_SHADER_STAGE_COMPUTE))
+			, layout			(env, PipelineLayout::Parameters::singleDescriptorSet(getDescriptorSetLayout()))
+			, pipelineCache		(env, PipelineCache::Parameters(1024u*1024u))
+		{}
+	};
+
+	static void initPrograms (SourceCollections& dst, Parameters)
+	{
+		Shader::initPrograms(dst, Shader::Parameters(ShaderModule::Parameters("comp"), VK_SHADER_STAGE_COMPUTE));
+	}
+
+	static Move<VkPipeline> create (const Environment& env, const Resources& res, const Parameters&)
+	{
+		const VkComputePipelineCreateInfo	pipelineInfo	=
+		{
+			VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+			DE_NULL,
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+				DE_NULL,
+				VK_SHADER_STAGE_COMPUTE,
+				*res.shader.object,
+				DE_NULL					// pSpecializationInfo
+			},
+			0u,							// flags
+			*res.layout.object,
+			(VkPipeline)0,				// basePipelineHandle
+			0u,							// basePipelineIndex
+		};
+
+		return createComputePipeline(env.vkd, env.device, *res.pipelineCache.object, &pipelineInfo);
+	}
+};
+
+struct DescriptorPool
+{
+	typedef VkDescriptorPool Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkDescriptorPoolUsage			usage;
+		deUint32						maxSets;
+		vector<VkDescriptorTypeCount>	typeCount;
+
+		Parameters (VkDescriptorPoolUsage					usage_,
+					deUint32								maxSets_,
+					const vector<VkDescriptorTypeCount>&	typeCount_)
+			: usage		(usage_)
+			, maxSets	(maxSets_)
+			, typeCount	(typeCount_)
+		{}
+
+		static Parameters singleType (VkDescriptorPoolUsage	usage,
+									  deUint32				maxSets,
+									  VkDescriptorType		type,
+									  deUint32				count)
+		{
+			vector<VkDescriptorTypeCount> typeCount;
+			typeCount.push_back(makeDescriptorTypeCount(type, count));
+			return Parameters(usage, maxSets, typeCount);
+		}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkDescriptorPool> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkDescriptorPoolCreateInfo	descriptorPoolInfo	=
+		{
+			VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+			DE_NULL,
+			params.usage,
+			params.maxSets,
+			(deUint32)params.typeCount.size(),
+			(params.typeCount.empty() ? DE_NULL : &params.typeCount[0])
+		};
+
+		return createDescriptorPool(env.vkd, env.device, &descriptorPoolInfo);
+	}
+};
+
+struct DescriptorSet
+{
+	typedef VkDescriptorSet Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkDescriptorPoolUsage			poolUsage;
+		VkDescriptorSetUsage			setUsage;
+		DescriptorSetLayout::Parameters	descriptorSetLayout;
+
+		Parameters (VkDescriptorPoolUsage					poolUsage_,
+					VkDescriptorSetUsage					setUsage_,
+					const DescriptorSetLayout::Parameters&	descriptorSetLayout_)
+			: poolUsage				(poolUsage_)
+			, setUsage				(setUsage_)
+			, descriptorSetLayout	(descriptorSetLayout_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<DescriptorPool>		descriptorPool;
+		Dependency<DescriptorSetLayout>	descriptorSetLayout;
+
+		static vector<VkDescriptorTypeCount> computeTypeCounts (const DescriptorSetLayout::Parameters& layout)
+		{
+			// \todo [2015-09-17 pyry] Add _RANGE etc. to enums
+			const deUint32					numDescTypes	= (deUint32)VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT+1u;
+			deUint32						countByType[numDescTypes];
+			vector<VkDescriptorTypeCount>	typeCounts;
+
+			std::fill(DE_ARRAY_BEGIN(countByType), DE_ARRAY_END(countByType), 0u);
+
+			for (vector<DescriptorSetLayout::Parameters::Binding>::const_iterator cur = layout.bindings.begin();
+				 cur != layout.bindings.end();
+				 ++cur)
+			{
+				DE_ASSERT((deUint32)cur->type < numDescTypes);
+				countByType[cur->type] += cur->arraySize;
+			}
+
+			for (deUint32 type = 0; type < numDescTypes; ++type)
+			{
+				if (countByType[type] > 0)
+					typeCounts.push_back(makeDescriptorTypeCount((VkDescriptorType)type, countByType[type]));
+			}
+
+			return typeCounts;
+		}
+
+		Resources (const Environment& env, const Parameters& params)
+			: descriptorPool		(env, DescriptorPool::Parameters(params.poolUsage, env.maxResourceConsumers, computeTypeCounts(params.descriptorSetLayout)))
+			, descriptorSetLayout	(env, params.descriptorSetLayout)
+		{
+		}
+	};
+
+	static Move<VkDescriptorSet> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		return allocDescriptorSet(env.vkd, env.device, *res.descriptorPool.object, params.setUsage, *res.descriptorSetLayout.object);
+	}
+};
+
+struct Framebuffer
+{
+	typedef VkFramebuffer Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		Parameters (void)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<ImageView>	colorAttachment;
+		Dependency<ImageView>	depthStencilAttachment;
+		Dependency<RenderPass>	renderPass;
+
+		Resources (const Environment& env, const Parameters&)
+			: colorAttachment			(env, ImageView::Parameters(Image::Parameters(VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
+																					  makeExtent3D(256, 256, 1),
+																					  1u, 1u, 1u,
+																					  VK_IMAGE_TILING_OPTIMAL,
+																					  VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+																					  VK_IMAGE_LAYOUT_UNDEFINED),
+																		 VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
+																		 makeChannelMappingRGBA(),
+																		 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)))
+			, depthStencilAttachment	(env, ImageView::Parameters(Image::Parameters(VK_IMAGE_TYPE_2D, VK_FORMAT_D16_UNORM,
+																					  makeExtent3D(256, 256, 1),
+																					  1u, 1u, 1u,
+																					  VK_IMAGE_TILING_OPTIMAL,
+																					  VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+																					  VK_IMAGE_LAYOUT_UNDEFINED),
+																		 VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_D16_UNORM,
+																		 makeChannelMappingRGBA(),
+																		 makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u)))
+			, renderPass				(env, RenderPass::Parameters())
+		{}
+	};
+
+	static Move<VkFramebuffer> create (const Environment& env, const Resources& res, const Parameters&)
+	{
+		const VkImageView				attachments[]	=
+		{
+			*res.colorAttachment.object,
+			*res.depthStencilAttachment.object,
+		};
+		const VkFramebufferCreateInfo	framebufferInfo	=
+		{
+			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+			DE_NULL,
+			*res.renderPass.object,
+			(deUint32)DE_LENGTH_OF_ARRAY(attachments),
+			attachments,
+			256u,										// width
+			256u,										// height
+			1u											// layers
+		};
+
+		return createFramebuffer(env.vkd, env.device, &framebufferInfo);
+	}
+};
+
+struct CmdPool
+{
+	typedef VkCmdPool Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		VkCmdPoolCreateFlags	flags;
+
+		Parameters (VkCmdPoolCreateFlags flags_)
+			: flags(flags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Resources (const Environment&, const Parameters&) {}
+	};
+
+	static Move<VkCmdPool> create (const Environment& env, const Resources&, const Parameters& params)
+	{
+		const VkCmdPoolCreateInfo	cmdPoolInfo	=
+		{
+			VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
+			DE_NULL,
+			env.queueFamilyIndex,
+			params.flags
+		};
+
+		return createCommandPool(env.vkd, env.device, &cmdPoolInfo);
+	}
+};
+
+struct CmdBuffer
+{
+	typedef VkCmdBuffer Type;
+
+	enum { MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT_OBJECTS };
+
+	struct Parameters
+	{
+		CmdPool::Parameters		cmdPool;
+		VkCmdBufferLevel		level;
+		VkCmdBufferCreateFlags	flags;
+
+		Parameters (const CmdPool::Parameters&	cmdPool_,
+					VkCmdBufferLevel			level_,
+					VkCmdBufferCreateFlags		flags_)
+			: cmdPool	(cmdPool_)
+			, level		(level_)
+			, flags		(flags_)
+		{}
+	};
+
+	struct Resources
+	{
+		Dependency<CmdPool>	cmdPool;
+
+		Resources (const Environment& env, const Parameters& params)
+			: cmdPool(env, params.cmdPool)
+		{}
+	};
+
+	static Move<VkCmdBuffer> create (const Environment& env, const Resources& res, const Parameters& params)
+	{
+		const VkCmdBufferCreateInfo	cmdBufferInfo	=
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+			DE_NULL,
+			*res.cmdPool.object,
+			params.level,
+			params.flags
+		};
+
+		return createCommandBuffer(env.vkd, env.device, &cmdBufferInfo);
+	}
+};
+
+// Test cases
+
+template<typename Object>
+tcu::TestStatus createSingleTest (Context& context, typename Object::Parameters params)
+{
+	const Environment					env	(context, 1u);
+	const typename Object::Resources	res	(env, params);
+
+	{
+		Unique<typename Object::Type>	obj	(Object::create(env, res, params));
+	}
+
+	return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+tcu::TestStatus createMultipleUniqueResourcesTest (Context& context, typename Object::Parameters params)
+{
+	const Environment					env		(context, 1u);
+	const typename Object::Resources	res0	(env, params);
+	const typename Object::Resources	res1	(env, params);
+	const typename Object::Resources	res2	(env, params);
+	const typename Object::Resources	res3	(env, params);
+
+	{
+		Unique<typename Object::Type>	obj0	(Object::create(env, res0, params));
+		Unique<typename Object::Type>	obj1	(Object::create(env, res1, params));
+		Unique<typename Object::Type>	obj2	(Object::create(env, res2, params));
+		Unique<typename Object::Type>	obj3	(Object::create(env, res3, params));
+	}
+
+	return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+tcu::TestStatus createMultipleSharedResourcesTest (Context& context, typename Object::Parameters params)
+{
+	const Environment					env	(context, 4u);
+	const typename Object::Resources	res	(env, params);
+
+	{
+		Unique<typename Object::Type>	obj0	(Object::create(env, res, params));
+		Unique<typename Object::Type>	obj1	(Object::create(env, res, params));
+		Unique<typename Object::Type>	obj2	(Object::create(env, res, params));
+		Unique<typename Object::Type>	obj3	(Object::create(env, res, params));
+	}
+
+	return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+tcu::TestStatus createMaxConcurrentTest (Context& context, typename Object::Parameters params)
+{
+	typedef Unique<typename Object::Type>	UniqueObject;
+	typedef SharedPtr<UniqueObject>			ObjectPtr;
+
+	const deUint32						numObjects	= Object::MAX_CONCURRENT;
+	const Environment					env			(context, numObjects);
+	const typename Object::Resources	res			(env, params);
+	vector<ObjectPtr>					objects		(numObjects);
+
+	context.getTestContext().getLog()
+		<< TestLog::Message << "Creating " << numObjects << " " << getTypeName<typename Object::Type>() << "s" << TestLog::EndMessage;
+
+	for (deUint32 ndx = 0; ndx < numObjects; ndx++)
+		objects[ndx] = ObjectPtr(new UniqueObject(Object::create(env, res, params)));
+
+	objects.clear();
+
+	return tcu::TestStatus::pass("Ok");
+}
+
+template<typename Object>
+class CreateThread : public ThreadGroupThread
+{
+public:
+	CreateThread (const Environment& env, const typename Object::Resources& resources, const typename Object::Parameters& params)
+		: m_env			(env)
+		, m_resources	(resources)
+		, m_params		(params)
+	{}
+
+	void runThread (void)
+	{
+		const int	numIters			= 100;
+		const int	itersBetweenSyncs	= 20;
+
+		for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
+		{
+			// Sync every Nth iteration to make entering driver at the same time more likely
+			if ((iterNdx % itersBetweenSyncs) == 0)
+				barrier();
+
+			{
+				Unique<typename Object::Type>	obj	(Object::create(m_env, m_resources, m_params));
+			}
+		}
+	}
+
+private:
+	const Environment&					m_env;
+	const typename Object::Resources&	m_resources;
+	const typename Object::Parameters&	m_params;
+};
+
+template<typename Object>
+tcu::TestStatus multithreadedCreateSharedResourcesTest (Context& context, typename Object::Parameters params)
+{
+	const deUint32						numThreads	= getDefaultTestThreadCount();
+	const Environment					env			(context, numThreads);
+	const typename Object::Resources	res			(env, params);
+	ThreadGroup							threads;
+
+	for (deUint32 ndx = 0; ndx < numThreads; ndx++)
+		threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(env, res, params)));
+
+	return threads.run();
+}
+
+template<typename Object>
+tcu::TestStatus multithreadedCreatePerThreadResourcesTest (Context& context, typename Object::Parameters params)
+{
+	typedef SharedPtr<typename Object::Resources>	ResPtr;
+
+	const deUint32		numThreads	= getDefaultTestThreadCount();
+	const Environment	env			(context, 1u);
+	vector<ResPtr>		resources	(numThreads);
+	ThreadGroup			threads;
+
+	for (deUint32 ndx = 0; ndx < numThreads; ndx++)
+	{
+		resources[ndx] = ResPtr(new typename Object::Resources(env, params));
+		threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(env, *resources[ndx], params)));
+	}
+
+	return threads.run();
+}
+
+struct EnvClone
+{
+	Device::Resources	deviceRes;
+	Unique<VkDevice>	device;
+	DeviceDriver		vkd;
+	Environment			env;
+
+	EnvClone (const Environment& parent, const Device::Parameters& deviceParams, deUint32 maxResourceConsumers)
+		: deviceRes	(parent, deviceParams)
+		, device	(Device::create(parent, deviceRes, deviceParams))
+		, vkd		(deviceRes.vki, *device)
+		, env		(parent.vkp, vkd, *device, deviceRes.queueFamilyIndex, parent.programBinaries, maxResourceConsumers)
+	{
+	}
+};
+
+template<typename Object>
+tcu::TestStatus multithreadedCreatePerThreadDeviceTest (Context& context, typename Object::Parameters params)
+{
+	typedef SharedPtr<EnvClone>						EnvPtr;
+	typedef SharedPtr<typename Object::Resources>	ResPtr;
+
+	const deUint32				numThreads		= getDefaultTestThreadCount();
+	const Device::Parameters	deviceParams	(context.getTestContext().getCommandLine().getVKDeviceId()-1u, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT);
+	const Environment			sharedEnv		(context, numThreads);			// For creating Device's
+	vector<EnvPtr>				perThreadEnv	(numThreads);
+	vector<ResPtr>				resources		(numThreads);
+	ThreadGroup					threads;
+
+	for (deUint32 ndx = 0; ndx < numThreads; ndx++)
+	{
+		perThreadEnv[ndx]	= EnvPtr(new EnvClone(sharedEnv, deviceParams, 1u));
+		resources[ndx]		= ResPtr(new typename Object::Resources(perThreadEnv[ndx]->env, params));
+
+		threads.add(MovePtr<ThreadGroupThread>(new CreateThread<Object>(perThreadEnv[ndx]->env, *resources[ndx], params)));
+	}
+
+	return threads.run();
+}
+
+// Utilities for creating groups
+
+template<typename Object>
+struct NamedParameters
+{
+	const char*						name;
+	typename Object::Parameters		parameters;
+};
+
+template<typename Object>
+struct CaseDescription
+{
+	typename FunctionInstance1<typename Object::Parameters>::Function	function;
+	const NamedParameters<Object>*										paramsBegin;
+	const NamedParameters<Object>*										paramsEnd;
+};
+
+#define EMPTY_CASE_DESC(OBJECT)	\
+	{ (FunctionInstance1<OBJECT::Parameters>::Function)DE_NULL, DE_NULL, DE_NULL }
+
+#define CASE_DESC(FUNCTION, CASES)	\
+	{ FUNCTION, DE_ARRAY_BEGIN(CASES), DE_ARRAY_END(CASES)	}
+
+struct CaseDescriptions
+{
+	CaseDescription<Instance>				instance;
+	CaseDescription<Device>					device;
+	CaseDescription<DeviceMemory>			deviceMemory;
+	CaseDescription<Buffer>					buffer;
+	CaseDescription<BufferView>				bufferView;
+	CaseDescription<Image>					image;
+	CaseDescription<ImageView>				imageView;
+	CaseDescription<Semaphore>				semaphore;
+	CaseDescription<Event>					event;
+	CaseDescription<Fence>					fence;
+	CaseDescription<QueryPool>				queryPool;
+	CaseDescription<ShaderModule>			shaderModule;
+	CaseDescription<Shader>					shader;
+	CaseDescription<PipelineCache>			pipelineCache;
+	CaseDescription<PipelineLayout>			pipelineLayout;
+	CaseDescription<RenderPass>				renderPass;
+	CaseDescription<GraphicsPipeline>		graphicsPipeline;
+	CaseDescription<ComputePipeline>		computePipeline;
+	CaseDescription<DescriptorSetLayout>	descriptorSetLayout;
+	CaseDescription<Sampler>				sampler;
+	CaseDescription<DescriptorPool>			descriptorPool;
+	CaseDescription<DescriptorSet>			descriptorSet;
+	CaseDescription<Framebuffer>			framebuffer;
+	CaseDescription<CmdPool>				cmdPool;
+	CaseDescription<CmdBuffer>				cmdBuffer;
+};
+
+template<typename Object>
+void addCases (const MovePtr<tcu::TestCaseGroup>& group, const CaseDescription<Object>& cases)
+{
+	for (const NamedParameters<Object>* cur = cases.paramsBegin; cur != cases.paramsEnd; ++cur)
+		addFunctionCase(group.get(), cur->name, "", cases.function, cur->parameters);
+}
+
+template<typename Object>
+void addCasesWithProgs (const MovePtr<tcu::TestCaseGroup>& group, const CaseDescription<Object>& cases)
+{
+	for (const NamedParameters<Object>* cur = cases.paramsBegin; cur != cases.paramsEnd; ++cur)
+		addFunctionCaseWithPrograms(group.get(), cur->name, "", Object::initPrograms, cases.function, cur->parameters);
+}
+
+tcu::TestCaseGroup* createGroup (tcu::TestContext& testCtx, const char* name, const char* desc, const CaseDescriptions& cases)
+{
+	MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, name, desc));
+
+	addCases			(group, cases.instance);
+	addCases			(group, cases.device);
+	addCases			(group, cases.deviceMemory);
+	addCases			(group, cases.buffer);
+	addCases			(group, cases.bufferView);
+	addCases			(group, cases.image);
+	addCases			(group, cases.imageView);
+	addCases			(group, cases.semaphore);
+	addCases			(group, cases.event);
+	addCases			(group, cases.fence);
+	addCases			(group, cases.queryPool);
+	addCases			(group, cases.sampler);
+	addCasesWithProgs	(group, cases.shaderModule);
+	addCasesWithProgs	(group, cases.shader);
+	addCases			(group, cases.pipelineCache);
+	addCases			(group, cases.pipelineLayout);
+	addCases			(group, cases.renderPass);
+	addCasesWithProgs	(group, cases.graphicsPipeline);
+	addCasesWithProgs	(group, cases.computePipeline);
+	addCases			(group, cases.descriptorSetLayout);
+	addCases			(group, cases.descriptorPool);
+	addCases			(group, cases.descriptorSet);
+	addCases			(group, cases.framebuffer);
+	addCases			(group, cases.cmdPool);
+	addCases			(group, cases.cmdBuffer);
+
+	return group.release();
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createObjectManagementTests (tcu::TestContext& testCtx)
+{
+	MovePtr<tcu::TestCaseGroup>	objectMgmtTests	(new tcu::TestCaseGroup(testCtx, "object_management", "Object management tests"));
+
+	const Image::Parameters		img1D			(VK_IMAGE_TYPE_1D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D(256,   1, 1), 1u,  4u, 1u, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
+	const Image::Parameters		img2D			(VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D( 64,  64, 1), 1u, 12u, 1u, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
+	const Image::Parameters		img3D			(VK_IMAGE_TYPE_3D, VK_FORMAT_R8G8B8A8_UNORM, makeExtent3D( 64,  64, 4), 1u,  1u, 1u, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_UNDEFINED);
+	const ImageView::Parameters	imgView1D		(img1D, VK_IMAGE_VIEW_TYPE_1D,			img1D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
+	const ImageView::Parameters	imgView1DArr	(img1D, VK_IMAGE_VIEW_TYPE_1D_ARRAY,	img1D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 4u));
+	const ImageView::Parameters	imgView2D		(img2D, VK_IMAGE_VIEW_TYPE_2D,			img2D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
+	const ImageView::Parameters	imgView2DArr	(img2D, VK_IMAGE_VIEW_TYPE_2D_ARRAY,	img2D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 8u));
+	const ImageView::Parameters	imgViewCube		(img2D, VK_IMAGE_VIEW_TYPE_CUBE,		img2D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 6u));
+	const ImageView::Parameters	imgViewCubeArr	(img2D, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	img2D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 12u));
+	const ImageView::Parameters	imgView3D		(img3D, VK_IMAGE_VIEW_TYPE_3D,			img3D.format, makeChannelMappingRGBA(), makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
+
+	const DescriptorSetLayout::Parameters	singleUboDescLayout	= DescriptorSetLayout::Parameters::single(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u, VK_SHADER_STAGE_VERTEX);
+
+	static NamedParameters<Instance>				s_instanceCases[]			=
+	{
+		{ "instance",					Instance::Parameters() },
+	};
+	// \note Device index may change - must not be static
+	const NamedParameters<Device>					s_deviceCases[]				=
+	{
+		{ "device",						Device::Parameters(testCtx.getCommandLine().getVKDeviceId()-1u, VK_QUEUE_GRAPHICS_BIT)	},
+	};
+	static const NamedParameters<DeviceMemory>			s_deviceMemCases[]				=
+	{
+		{ "device_memory_small",		DeviceMemory::Parameters(1024, 0u)	},
+	};
+	static const NamedParameters<Buffer>				s_bufferCases[]					=
+	{
+		{ "buffer_uniform_small",		Buffer::Parameters(1024u,			VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),	},
+		{ "buffer_uniform_large",		Buffer::Parameters(1024u*1024u*16u,	VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),	},
+		{ "buffer_storage_small",		Buffer::Parameters(1024u,			VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),	},
+		{ "buffer_storage_large",		Buffer::Parameters(1024u*1024u*16u,	VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),	},
+	};
+	static const NamedParameters<BufferView>			s_bufferViewCases[]				=
+	{
+		{ "buffer_view_uniform_r8g8b8a8_unorm",	BufferView::Parameters(Buffer::Parameters(8192u, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT), VK_FORMAT_R8G8B8A8_UNORM, 0u, 4096u)	},
+		{ "buffer_view_storage_r8g8b8a8_unorm",	BufferView::Parameters(Buffer::Parameters(8192u, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), VK_FORMAT_R8G8B8A8_UNORM, 0u, 4096u)	},
+	};
+	static const NamedParameters<Image>					s_imageCases[]					=
+	{
+		{ "image_1d",					img1D		},
+		{ "image_2d",					img2D		},
+		{ "image_3d",					img3D		},
+	};
+	static const NamedParameters<ImageView>				s_imageViewCases[]				=
+	{
+		{ "image_view_1d",				imgView1D		},
+		{ "image_view_1d_arr",			imgView1DArr	},
+		{ "image_view_2d",				imgView2D		},
+		{ "image_view_2d_arr",			imgView2DArr	},
+		{ "image_view_cube",			imgViewCube		},
+		{ "image_view_cube_arr",		imgViewCubeArr	},
+		{ "image_view_3d",				imgView3D		},
+	};
+	static const NamedParameters<Semaphore>				s_semaphoreCases[]				=
+	{
+		{ "semaphore",					Semaphore::Parameters(0u),	}
+	};
+	static const NamedParameters<Event>					s_eventCases[]					=
+	{
+		{ "event",						Event::Parameters(0u)		}
+	};
+	static const NamedParameters<Fence>					s_fenceCases[]					=
+	{
+		{ "fence",						Fence::Parameters(0u)								},
+		{ "fence_signaled",				Fence::Parameters(VK_FENCE_CREATE_SIGNALED_BIT)		}
+	};
+	static const NamedParameters<QueryPool>				s_queryPoolCases[]				=
+	{
+		{ "query_pool",					QueryPool::Parameters(VK_QUERY_TYPE_OCCLUSION, 1u, 0u)	}
+	};
+	static const NamedParameters<ShaderModule>			s_shaderModuleCases[]			=
+	{
+		{ "shader_module",				ShaderModule::Parameters("test")	}
+	};
+	static const NamedParameters<Shader>				s_shaderCases[]					=
+	{
+		{ "shader_vertex",				Shader::Parameters(ShaderModule::Parameters("vert"), VK_SHADER_STAGE_VERTEX)	},
+		{ "shader_fragment",			Shader::Parameters(ShaderModule::Parameters("frag"), VK_SHADER_STAGE_FRAGMENT)	},
+		{ "shader_compute",				Shader::Parameters(ShaderModule::Parameters("comp"), VK_SHADER_STAGE_COMPUTE)	},
+	};
+	static const NamedParameters<PipelineCache>			s_pipelineCacheCases[]			=
+	{
+		{ "pipeline_cache",				PipelineCache::Parameters(8u*1024u*1024u)	}
+	};
+	static const NamedParameters<PipelineLayout>		s_pipelineLayoutCases[]			=
+	{
+		{ "pipeline_layout_empty",		PipelineLayout::Parameters::empty()										},
+		{ "pipeline_layout_single",		PipelineLayout::Parameters::singleDescriptorSet(singleUboDescLayout)	}
+	};
+	static const NamedParameters<RenderPass>			s_renderPassCases[]				=
+	{
+		{ "render_pass",				RenderPass::Parameters()		}
+	};
+	static const NamedParameters<GraphicsPipeline>		s_graphicsPipelineCases[]		=
+	{
+		{ "graphics_pipeline",			GraphicsPipeline::Parameters()	}
+	};
+	static const NamedParameters<ComputePipeline>		s_computePipelineCases[]		=
+	{
+		{ "compute_pipeline",			ComputePipeline::Parameters()	}
+	};
+	static const NamedParameters<DescriptorSetLayout>	s_descriptorSetLayoutCases[]	=
+	{
+		{ "descriptor_set_layout_empty",	DescriptorSetLayout::Parameters::empty()	},
+		{ "descriptor_set_layout_single",	singleUboDescLayout							}
+	};
+	static const NamedParameters<Sampler>				s_samplerCases[]				=
+	{
+		{ "sampler",					Sampler::Parameters()	}
+	};
+	static const NamedParameters<DescriptorPool>		s_descriptorPoolCases[]			=
+	{
+		{ "descriptor_pool_one_shot",	DescriptorPool::Parameters::singleType(VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT,	4u, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u)	},
+		{ "descriptor_pool_dynamic",	DescriptorPool::Parameters::singleType(VK_DESCRIPTOR_POOL_USAGE_DYNAMIC,	4u, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u)	}
+	};
+	static const NamedParameters<DescriptorSet>			s_descriptorSetCases[]			=
+	{
+		{ "descriptor_set_one_shot",	DescriptorSet::Parameters(VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, singleUboDescLayout)	},
+		{ "descriptor_set_static",		DescriptorSet::Parameters(VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, VK_DESCRIPTOR_SET_USAGE_STATIC, singleUboDescLayout)	}
+	};
+	static const NamedParameters<Framebuffer>			s_framebufferCases[]			=
+	{
+		{ "framebuffer",				Framebuffer::Parameters()	}
+	};
+	static const NamedParameters<CmdPool>				s_cmdPoolCases[]				=
+	{
+		{ "cmd_pool",					CmdPool::Parameters(0u)									},
+		{ "cmd_pool_transient",			CmdPool::Parameters(VK_CMD_POOL_CREATE_TRANSIENT_BIT)	}
+	};
+	static const NamedParameters<CmdBuffer>				s_cmdBufferCases[]				=
+	{
+		{ "cmd_buffer_primary",			CmdBuffer::Parameters(CmdPool::Parameters(0u), VK_CMD_BUFFER_LEVEL_PRIMARY, 0u)		},
+		{ "cmd_buffer_secondary",		CmdBuffer::Parameters(CmdPool::Parameters(0u), VK_CMD_BUFFER_LEVEL_SECONDARY, 0u)	}
+	};
+
+	static const CaseDescriptions	s_createSingleGroup	=
+	{
+		CASE_DESC(createSingleTest	<Instance>,					s_instanceCases),
+		CASE_DESC(createSingleTest	<Device>,					s_deviceCases),
+		CASE_DESC(createSingleTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(createSingleTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(createSingleTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(createSingleTest	<Image>,					s_imageCases),
+		CASE_DESC(createSingleTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(createSingleTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(createSingleTest	<Event>,					s_eventCases),
+		CASE_DESC(createSingleTest	<Fence>,					s_fenceCases),
+		CASE_DESC(createSingleTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(createSingleTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(createSingleTest	<Shader>,					s_shaderCases),
+		CASE_DESC(createSingleTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(createSingleTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(createSingleTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(createSingleTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(createSingleTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(createSingleTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(createSingleTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(createSingleTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(createSingleTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(createSingleTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(createSingleTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(createSingleTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "single", "Create single object", s_createSingleGroup));
+
+	static const CaseDescriptions	s_createMultipleUniqueResourcesGroup	=
+	{
+		CASE_DESC(createMultipleUniqueResourcesTest	<Instance>,					s_instanceCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Device>,					s_deviceCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Image>,					s_imageCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Event>,					s_eventCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Fence>,					s_fenceCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Shader>,					s_shaderCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(createMultipleUniqueResourcesTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "multiple_unique_resources", "Multiple objects with per-object unique resources", s_createMultipleUniqueResourcesGroup));
+
+	static const CaseDescriptions	s_createMultipleSharedResourcesGroup	=
+	{
+		EMPTY_CASE_DESC(Instance), // No resources used
+		CASE_DESC(createMultipleSharedResourcesTest	<Device>,					s_deviceCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Image>,					s_imageCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Event>,					s_eventCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Fence>,					s_fenceCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Shader>,					s_shaderCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(createMultipleSharedResourcesTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "multiple_shared_resources", "Multiple objects with shared resources", s_createMultipleSharedResourcesGroup));
+
+	static const CaseDescriptions	s_createMaxConcurrentGroup	=
+	{
+		CASE_DESC(createMaxConcurrentTest	<Instance>,					s_instanceCases),
+		CASE_DESC(createMaxConcurrentTest	<Device>,					s_deviceCases),
+		CASE_DESC(createMaxConcurrentTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(createMaxConcurrentTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(createMaxConcurrentTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(createMaxConcurrentTest	<Image>,					s_imageCases),
+		CASE_DESC(createMaxConcurrentTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(createMaxConcurrentTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(createMaxConcurrentTest	<Event>,					s_eventCases),
+		CASE_DESC(createMaxConcurrentTest	<Fence>,					s_fenceCases),
+		CASE_DESC(createMaxConcurrentTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(createMaxConcurrentTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(createMaxConcurrentTest	<Shader>,					s_shaderCases),
+		CASE_DESC(createMaxConcurrentTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(createMaxConcurrentTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(createMaxConcurrentTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(createMaxConcurrentTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(createMaxConcurrentTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(createMaxConcurrentTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(createMaxConcurrentTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(createMaxConcurrentTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(createMaxConcurrentTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(createMaxConcurrentTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(createMaxConcurrentTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(createMaxConcurrentTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "max_concurrent", "Maximum number of concurrently live objects", s_createMaxConcurrentGroup));
+
+	static const CaseDescriptions	s_multithreadedCreatePerThreadDeviceGroup	=
+	{
+		EMPTY_CASE_DESC(Instance),	// Does not make sense
+		EMPTY_CASE_DESC(Device),	// Does not make sense
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Image>,					s_imageCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Event>,					s_eventCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Fence>,					s_fenceCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Shader>,					s_shaderCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadDeviceTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "multithreaded_per_thread_device", "Multithreaded object construction with per-thread device ", s_multithreadedCreatePerThreadDeviceGroup));
+
+	static const CaseDescriptions	s_multithreadedCreatePerThreadResourcesGroup	=
+	{
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Instance>,					s_instanceCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Device>,					s_deviceCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Image>,					s_imageCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Event>,					s_eventCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Fence>,					s_fenceCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Shader>,					s_shaderCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<DescriptorPool>,			s_descriptorPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<DescriptorSet>,			s_descriptorSetCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<CmdPool>,					s_cmdPoolCases),
+		CASE_DESC(multithreadedCreatePerThreadResourcesTest	<CmdBuffer>,				s_cmdBufferCases),
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "multithreaded_per_thread_resources", "Multithreaded object construction with per-thread resources", s_multithreadedCreatePerThreadResourcesGroup));
+
+	static const CaseDescriptions	s_multithreadedCreateSharedResourcesGroup	=
+	{
+		EMPTY_CASE_DESC(Instance),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Device>,					s_deviceCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<DeviceMemory>,				s_deviceMemCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Buffer>,					s_bufferCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<BufferView>,				s_bufferViewCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Image>,					s_imageCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<ImageView>,				s_imageViewCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Semaphore>,				s_semaphoreCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Event>,					s_eventCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Fence>,					s_fenceCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<QueryPool>,				s_queryPoolCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<ShaderModule>,				s_shaderModuleCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Shader>,					s_shaderCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<PipelineCache>,			s_pipelineCacheCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<PipelineLayout>,			s_pipelineLayoutCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<RenderPass>,				s_renderPassCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<GraphicsPipeline>,			s_graphicsPipelineCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<ComputePipeline>,			s_computePipelineCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<DescriptorSetLayout>,		s_descriptorSetLayoutCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Sampler>,					s_samplerCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<DescriptorPool>,			s_descriptorPoolCases),
+		EMPTY_CASE_DESC(DescriptorSet),		// \note Needs per-thread DescriptorPool
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<Framebuffer>,				s_framebufferCases),
+		CASE_DESC(multithreadedCreateSharedResourcesTest	<CmdPool>,					s_cmdPoolCases),
+		EMPTY_CASE_DESC(CmdBuffer),			// \note Needs per-thread CmdPool
+	};
+	objectMgmtTests->addChild(createGroup(testCtx, "multithreaded_shared_resources", "Multithreaded object construction with shared resources", s_multithreadedCreateSharedResourcesGroup));
+
+	return objectMgmtTests.release();
+}
+
+} // api
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.hpp b/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.hpp
new file mode 100644
index 0000000..c3bfade
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiObjectManagementTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTAPIOBJECTMANAGEMENTTESTS_HPP
+#define _VKTAPIOBJECTMANAGEMENTTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Object management tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+tcu::TestCaseGroup*		createObjectManagementTests		(tcu::TestContext& testCtx);
+
+} // api
+} // vkt
+
+#endif // _VKTAPIOBJECTMANAGEMENTTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.cpp
new file mode 100644
index 0000000..7fefdd5
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.cpp
@@ -0,0 +1,799 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Simple Smoke Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiTests.hpp"
+
+#include "vktTestCaseUtil.hpp"
+
+#include "vkDefs.hpp"
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+
+#include "deUniquePtr.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+namespace
+{
+
+using namespace vk;
+using std::vector;
+using tcu::TestLog;
+using de::UniquePtr;
+
+tcu::TestStatus createSamplerTest (Context& context)
+{
+	const VkDevice			vkDevice	= context.getDevice();
+	const DeviceInterface&	vk			= context.getDeviceInterface();
+
+	{
+		const struct VkSamplerCreateInfo		samplerInfo	=
+		{
+			VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,		//	VkStructureType		sType;
+			DE_NULL,									//	const void*			pNext;
+			VK_TEX_FILTER_NEAREST,						//	VkTexFilter			magFilter;
+			VK_TEX_FILTER_NEAREST,						//	VkTexFilter			minFilter;
+			VK_TEX_MIPMAP_MODE_BASE,					//	VkTexMipmapMode		mipMode;
+			VK_TEX_ADDRESS_MODE_CLAMP,					//	VkTexAddressMode	addressU;
+			VK_TEX_ADDRESS_MODE_CLAMP,					//	VkTexAddressMode	addressV;
+			VK_TEX_ADDRESS_MODE_CLAMP,					//	VkTexAddressMode	addressW;
+			0.0f,										//	float				mipLodBias;
+			0.0f,										//	float				maxAnisotropy;
+			DE_FALSE,									//	VkBool32			compareEnable;
+			VK_COMPARE_OP_ALWAYS,						//	VkCompareOp			compareOp;
+			0.0f,										//	float				minLod;
+			0.0f,										//	float				maxLod;
+			VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	//	VkBorderColor		borderColor;
+			VK_FALSE,									//	VKBool32			unnormalizedCoords;
+		};
+
+		Move<VkSampler>			tmpSampler	= createSampler(vk, vkDevice, &samplerInfo);
+		Move<VkSampler>			tmp2Sampler;
+
+		tmp2Sampler = tmpSampler;
+
+		const Unique<VkSampler>	sampler		(tmp2Sampler);
+	}
+
+	return tcu::TestStatus::pass("Creating sampler succeeded");
+}
+
+void createShaderProgs (SourceCollections& dst)
+{
+	dst.glslSources.add("test") << glu::VertexSource(
+		"#version 300 es\n"
+		"in highp vec4 a_position;\n"
+		"void main (void) { gl_Position = a_position; }\n");
+}
+
+tcu::TestStatus createShaderModuleTest (Context& context)
+{
+	const VkDevice					vkDevice	= context.getDevice();
+	const DeviceInterface&			vk			= context.getDeviceInterface();
+	const Unique<VkShaderModule>	shader		(createShaderModule(vk, vkDevice, context.getBinaryCollection().get("test"), 0));
+
+	return tcu::TestStatus::pass("Creating shader module succeeded");
+}
+
+void createTriangleAsmProgs (SourceCollections& dst)
+{
+	dst.spirvAsmSources.add("vert") <<
+		"		 OpSource ESSL 300\n"
+		"		 OpCapability Shader\n"
+		"%1 =	 OpExtInstImport \"GLSL.std.450\"\n"
+		"		 OpMemoryModel Logical GLSL450\n"
+		"		 OpEntryPoint Vertex %4 \"main\" %10 %12 %16 %17\n"
+		"		 OpName %4 \"main\"\n"
+		"		 OpName %10 \"gl_Position\"\n"
+		"		 OpName %12 \"a_position\"\n"
+		"		 OpName %16 \"gl_VertexID\"\n"
+		"		 OpName %17 \"gl_InstanceID\"\n"
+		"		 OpDecorate %10 BuiltIn Position\n"
+		"		 OpDecorate %12 Location 0\n"
+		"		 OpDecorate %16 BuiltIn VertexId\n"
+		"		 OpDecorate %17 BuiltIn InstanceId\n"
+		"%2 =	 OpTypeVoid\n"
+		"%3 =	 OpTypeFunction %2\n"
+		"%7 =	 OpTypeFloat 32\n"
+		"%8 =	 OpTypeVector %7 4\n"
+		"%9 =	 OpTypePointer Output %8\n"
+		"%10 =	 OpVariable %9 Output\n"
+		"%11 =	 OpTypePointer Input %8\n"
+		"%12 =	 OpVariable %11 Input\n"
+		"%14 =	 OpTypeInt 32 1\n"
+		"%15 =	 OpTypePointer Input %14\n"
+		"%16 =	 OpVariable %15 Input\n"
+		"%17 =	 OpVariable %15 Input\n"
+		"%4 =	 OpFunction %2 None %3\n"
+		"%5 =	 OpLabel\n"
+		"%13 =	 OpLoad %8 %12\n"
+		"		 OpStore %10 %13\n"
+		"		 OpBranch %6\n"
+		"%6 =	 OpLabel\n"
+		"		 OpReturn\n"
+		"		 OpFunctionEnd\n";
+	dst.spirvAsmSources.add("frag") <<
+		"		OpSource ESSL 300\n"
+		"		OpCapability Shader\n"
+		"%1 =	OpExtInstImport \"GLSL.std.450\"\n"
+		"		OpMemoryModel Logical GLSL450\n"
+		"		OpEntryPoint Fragment %4 \"main\" %10\n"
+		"		OpExecutionMode %4 OriginLowerLeft\n"
+		"		OpName %4 \"main\"\n"
+		"		OpName %10 \"o_color\"\n"
+		"		OpDecorate %10 RelaxedPrecision\n"
+		"		OpDecorate %10 Location 0\n"
+		"%2 =	OpTypeVoid\n"
+		"%3 =	OpTypeFunction %2\n"
+		"%7 =	OpTypeFloat 32\n"
+		"%8 =	OpTypeVector %7 4\n"
+		"%9 =	OpTypePointer Output %8\n"
+		"%10 =	OpVariable %9 Output\n"
+		"%11 =	OpConstant %7 1065353216\n"
+		"%12 =	OpConstant %7 0\n"
+		"%13 =	OpConstantComposite %8 %11 %12 %11 %11\n"
+		"%4 =	OpFunction %2 None %3\n"
+		"%5 =	OpLabel\n"
+		"		OpStore %10 %13\n"
+		"		OpBranch %6\n"
+		"%6 =	OpLabel\n"
+		"		OpReturn\n"
+		"		OpFunctionEnd\n";
+}
+
+void createTriangleProgs (SourceCollections& dst)
+{
+	dst.glslSources.add("vert") << glu::VertexSource(
+		"#version 300 es\n"
+		"layout(location = 0) in highp vec4 a_position;\n"
+		"void main (void) { gl_Position = a_position; }\n");
+	dst.glslSources.add("frag") << glu::FragmentSource(
+		"#version 300 es\n"
+		"layout(location = 0) out lowp vec4 o_color;\n"
+		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
+}
+
+tcu::TestStatus renderTriangleTest (Context& context)
+{
+	const VkDevice							vkDevice				= context.getDevice();
+	const DeviceInterface&					vk						= context.getDeviceInterface();
+	const VkQueue							queue					= context.getUniversalQueue();
+	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
+	SimpleAllocator							memAlloc				(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+	const tcu::IVec2						renderSize				(256, 256);
+
+	const tcu::Vec4							vertices[]				=
+	{
+		tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
+		tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
+		tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
+	};
+
+	const VkBufferCreateInfo				vertexBufferParams		=
+	{
+		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	//	VkStructureType		sType;
+		DE_NULL,								//	const void*			pNext;
+		(VkDeviceSize)sizeof(vertices),			//	VkDeviceSize		size;
+		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		//	VkBufferUsageFlags	usage;
+		0u,										//	VkBufferCreateFlags	flags;
+		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		(memAlloc.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;
+		imageSizeBytes,								//	VkDeviceSize		size;
+		VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,	//	VkBufferUsageFlags	usage;
+		0u,											//	VkBufferCreateFlags	flags;
+		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	(memAlloc.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;
+		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;
+		1u,																		//	deUint32			samples;
+		VK_IMAGE_TILING_OPTIMAL,												//	VkImageTiling		tiling;
+		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	//	VkImageUsageFlags	usage;
+		0u,																		//	VkImageCreateFlags	flags;
+		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				(memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any));
+
+	VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageMemory->getMemory(), imageMemory->getOffset()));
+
+	const VkAttachmentDescription			colorAttDesc			=
+	{
+		VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,		//	VkStructureType					sType;
+		DE_NULL,										//	const void*						pNext;
+		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat						format;
+		1u,												//	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;
+		0u,												//	VkAttachmentDescriptionFlags	flags;
+	};
+	const VkAttachmentReference				colorAttRef				=
+	{
+		0u,												//	deUint32		attachment;
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout	layout;
+	};
+	const VkSubpassDescription				subpassDesc				=
+	{
+		VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,			//	VkStructureType					sType;
+		DE_NULL,										//	const void*						pNext;
+		VK_PIPELINE_BIND_POINT_GRAPHICS,				//	VkPipelineBindPoint				pipelineBindPoint;
+		0u,												//	VkSubpassDescriptionFlags		flags;
+		0u,												//	deUint32						inputCount;
+		DE_NULL,										//	const VkAttachmentReference*	pInputAttachments;
+		1u,												//	deUint32						colorCount;
+		&colorAttRef,									//	const VkAttachmentReference*	pColorAttachments;
+		DE_NULL,										//	const VkAttachmentReference*	pResolveAttachments;
+		{ VK_NO_ATTACHMENT, VK_IMAGE_LAYOUT_GENERAL },	//	VkAttachmentReference			depthStencilAttachment;
+		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;
+		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;
+		*image,											//	VkImage						image;
+		VK_IMAGE_VIEW_TYPE_2D,							//	VkImageViewType				viewType;
+		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat					format;
+		{
+			VK_CHANNEL_SWIZZLE_R,
+			VK_CHANNEL_SWIZZLE_G,
+			VK_CHANNEL_SWIZZLE_B,
+			VK_CHANNEL_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;
+		0u,												//	VkImageViewCreateFlags		flags;
+	};
+	const Unique<VkImageView>				colorAttView			(createImageView(vk, vkDevice, &colorAttViewParams));
+
+	const Unique<VkShaderModule>			vertShaderModule		(createShaderModule(vk, vkDevice, context.getBinaryCollection().get("vert"), 0));
+	const VkShaderCreateInfo				vertShaderParams		=
+	{
+		VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			//	VkStructureType		sType;
+		DE_NULL,										//	const void*			pNext;
+		*vertShaderModule,								//	VkShaderModule		module;
+		"main",											//	const char*			pName;
+		0u,												//	VkShaderCreateFlags	flags;
+		VK_SHADER_STAGE_VERTEX,							//	VkShaderStage		stage;
+	};
+	const Unique<VkShader>					vertShader				(createShader(vk, vkDevice, &vertShaderParams));
+	const Unique<VkShaderModule>			fragShaderModule		(createShaderModule(vk, vkDevice, context.getBinaryCollection().get("frag"), 0));
+	const VkShaderCreateInfo				fragShaderParams		=
+	{
+		VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			//	VkStructureType		sType;
+		DE_NULL,										//	const void*			pNext;
+		*fragShaderModule,								//	VkShaderModule		module;
+		"main",											//	const char*			pName;
+		0u,												//	VkShaderCreateFlags	flags;
+		VK_SHADER_STAGE_FRAGMENT,						//	VkShaderStage		stage;
+	};
+	const Unique<VkShader>					fragShader				(createShader(vk, vkDevice, &fragShaderParams));
+
+	// Pipeline layout
+	const VkPipelineLayoutCreateInfo		pipelineLayoutParams	=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,			//	VkStructureType					sType;
+		DE_NULL,												//	const void*						pNext;
+		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
+	const VkSpecializationInfo				emptyShaderSpecParams	=
+	{
+		0u,														//	deUint32						mapEntryCount;
+		DE_NULL,												//	const VkSpecializationMapEntry*	pMap;
+		0,														//	const deUintptr					dataSize;
+		DE_NULL,												//	const void*						pData;
+	};
+	const VkPipelineShaderStageCreateInfo	shaderStageParams[]	=
+	{
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType				sType;
+			DE_NULL,												//	const void*					pNext;
+			VK_SHADER_STAGE_VERTEX,									//	VkShaderStage				stage;
+			*vertShader,											//	VkShader					shader;
+			&emptyShaderSpecParams,									//	const VkSpecializationInfo*	pSpecializationInfo;
+		},
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType				sType;
+			DE_NULL,												//	const void*					pNext;
+			VK_SHADER_STAGE_FRAGMENT,								//	VkShaderStage				stage;
+			*fragShader,											//	VkShader					shader;
+			&emptyShaderSpecParams,									//	const VkSpecializationInfo*	pSpecializationInfo;
+		}
+	};
+	const VkPipelineDepthStencilStateCreateInfo	depthStencilParams		=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	//	VkStructureType		sType;
+		DE_NULL,													//	const void*			pNext;
+		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;
+		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;
+		1u,															//	deUint32		rasterSamples;
+		DE_FALSE,													//	deUint32		sampleShadingEnable;
+		0.0f,														//	float			minSampleShading;
+		&sampleMask,												//	VkSampleMask	sampleMask;
+	};
+	const VkPipelineRasterStateCreateInfo		rasterParams			=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,	//	VkStructureType	sType;
+		DE_NULL,												//	const void*		pNext;
+		DE_TRUE,												//	deUint32		depthClipEnable;
+		DE_FALSE,												//	deUint32		rasterizerDiscardEnable;
+		VK_FILL_MODE_SOLID,										//	VkFillMode		fillMode;
+		VK_CULL_MODE_NONE,										//	VkCullMode		cullMode;
+		VK_FRONT_FACE_CCW,										//	VkFrontFace		frontFace;
+		VK_FALSE,												//	VkBool32		depthBiasEnable;
+		0.0f,													//	float			depthBias;
+		0.0f,													//	float			depthBiasClamp;
+		0.0f,													//	float			slopeScaledDepthBias;
+		1.0f,													//	float			lineWidth;
+	};
+	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams	=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType		sType;
+		DE_NULL,														//	const void*			pNext;
+		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							//	VkPrimitiveTopology	topology;
+		DE_FALSE,														//	deUint32			primitiveRestartEnable;
+	};
+	const VkVertexInputBindingDescription		vertexBinding0			=
+	{
+		0u,														//	deUint32				binding;
+		(deUint32)sizeof(tcu::Vec4),							//	deUint32				strideInBytes;
+		VK_VERTEX_INPUT_STEP_RATE_VERTEX,						//	VkVertexInputStepRate	stepRate;
+	};
+	const VkVertexInputAttributeDescription		vertexAttrib0			=
+	{
+		0u,														//	deUint32	location;
+		0u,														//	deUint32	binding;
+		VK_FORMAT_R32G32B32A32_SFLOAT,							//	VkFormat	format;
+		0u,														//	deUint32	offsetInBytes;
+	};
+	const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams	=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
+		DE_NULL,													//	const void*									pNext;
+		1u,															//	deUint32									bindingCount;
+		&vertexBinding0,											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
+		1u,															//	deUint32									attributeCount;
+		&vertexAttrib0,												//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+	};
+	const VkPipelineColorBlendAttachmentState	attBlendParams			=
+	{
+		DE_FALSE,																//	deUint32		blendEnable;
+		VK_BLEND_ONE,															//	VkBlend			srcBlendColor;
+		VK_BLEND_ZERO,															//	VkBlend			destBlendColor;
+		VK_BLEND_OP_ADD,														//	VkBlendOp		blendOpColor;
+		VK_BLEND_ONE,															//	VkBlend			srcBlendAlpha;
+		VK_BLEND_ZERO,															//	VkBlend			destBlendAlpha;
+		VK_BLEND_OP_ADD,														//	VkBlendOp		blendOpAlpha;
+		VK_CHANNEL_R_BIT|VK_CHANNEL_G_BIT|VK_CHANNEL_B_BIT|VK_CHANNEL_A_BIT,	//	VkChannelFlags	channelWriteMask;
+	};
+	const VkPipelineColorBlendStateCreateInfo	blendParams				=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
+		DE_NULL,													//	const void*									pNext;
+		DE_FALSE,													//	VkBool32									alphaToCoverageEnable;
+		DE_FALSE,													//	VkBool32									alphaToOneEnable;
+		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 VkPipelineDynamicStateCreateInfo	dynamicStateInfo		=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType			sType;
+		DE_NULL,												//	const void*				pNext;
+		0u,														//	deUint32				dynamicStateCount;
+		DE_NULL													//	const VkDynamicState*	pDynamicStates;
+	};
+	const VkGraphicsPipelineCreateInfo		pipelineParams			=
+	{
+		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,		//	VkStructureType									sType;
+		DE_NULL,												//	const void*										pNext;
+		(deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),		//	deUint32										stageCount;
+		shaderStageParams,										//	const VkPipelineShaderStageCreateInfo*			pStages;
+		&vertexInputStateParams,								//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
+		&inputAssemblyParams,									//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
+		DE_NULL,												//	const VkPipelineTessellationStateCreateInfo*	pTessellationState;
+		&viewportParams,										//	const VkPipelineViewportStateCreateInfo*		pViewportState;
+		&rasterParams,											//	const VkPipelineRasterStateCreateInfo*			pRasterState;
+		&multisampleParams,										//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
+		&depthStencilParams,									//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
+		&blendParams,											//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
+		&dynamicStateInfo,										//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
+		0u,														//	VkPipelineCreateFlags							flags;
+		*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;
+		*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 VkCmdPoolCreateInfo				cmdPoolParams			=
+	{
+		VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,						//	VkStructureType			sType;
+		DE_NULL,													//	const void*				pNext;
+		queueFamilyIndex,											//	deUint32				queueFamilyIndex;
+		VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT					//	VkCmdPoolCreateFlags	flags;
+	};
+	const Unique<VkCmdPool>					cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
+
+	// Command buffer
+	const VkCmdBufferCreateInfo				cmdBufParams			=
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,				//	VkStructureType			sType;
+		DE_NULL,												//	const void*				pNext;
+		*cmdPool,												//	VkCmdPool				pool;
+		VK_CMD_BUFFER_LEVEL_PRIMARY,							//	VkCmdBufferLevel		level;
+		0u,														//	VkCmdBufferCreateFlags	flags;
+	};
+	const Unique<VkCmdBuffer>				cmdBuf					(createCommandBuffer(vk, vkDevice, &cmdBufParams));
+
+	const VkCmdBufferBeginInfo				cmdBufBeginParams		=
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,				//	VkStructureType				sType;
+		DE_NULL,												//	const void*					pNext;
+		0u,														//	VkCmdBufferOptimizeFlags	flags;
+		DE_NULL,												//	VkRenderPass				renderPass;
+		0u,														//	deUint32					subpass;
+		DE_NULL,												//	VkFramebuffer				framebuffer;
+	};
+
+	// Record commands
+	VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
+
+	{
+		const VkMemoryBarrier		vertFlushBarrier	=
+		{
+			VK_STRUCTURE_TYPE_MEMORY_BARRIER,			//	VkStructureType		sType;
+			DE_NULL,									//	const void*			pNext;
+			VK_MEMORY_OUTPUT_HOST_WRITE_BIT,			//	VkMemoryOutputFlags	outputMask;
+			VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT,	//	VkMemoryInputFlags	inputMask;
+		};
+		const VkImageMemoryBarrier	colorAttBarrier		=
+		{
+			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
+			DE_NULL,									//	const void*				pNext;
+			0u,											//	VkMemoryOutputFlags		outputMask;
+			VK_MEMORY_INPUT_COLOR_ATTACHMENT_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;
+		};
+		const void*				barriers[]				= { &vertFlushBarrier, &colorAttBarrier };
+		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GPU_COMMANDS, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	{
+		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_RENDER_PASS_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, 3u, 1u, 0u, 0u);
+	vk.cmdEndRenderPass(*cmdBuf);
+
+	{
+		const VkImageMemoryBarrier	renderFinishBarrier	=
+		{
+			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
+			DE_NULL,									//	const void*				pNext;
+			VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,		//	VkMemoryOutputFlags		outputMask;
+			VK_MEMORY_INPUT_TRANSFER_BIT,				//	VkMemoryInputFlags		inputMask;
+			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout			oldLayout;
+			VK_IMAGE_LAYOUT_TRANSFER_SOURCE_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;
+		};
+		const void*				barriers[]				= { &renderFinishBarrier };
+		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS, VK_PIPELINE_STAGE_TRANSFER_BIT, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	{
+		const VkBufferImageCopy	copyParams	=
+		{
+			(VkDeviceSize)0u,						//	VkDeviceSize			bufferOffset;
+			(deUint32)renderSize.x(),				//	deUint32				bufferRowLength;
+			(deUint32)renderSize.y(),				//	deUint32				bufferImageHeight;
+			{
+				VK_IMAGE_ASPECT_COLOR,					//	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_SOURCE_OPTIMAL, *readImageBuffer, 1u, &copyParams);
+	}
+
+	{
+		const VkBufferMemoryBarrier	copyFinishBarrier	=
+		{
+			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	//	VkStructureType		sType;
+			DE_NULL,									//	const void*			pNext;
+			VK_MEMORY_OUTPUT_TRANSFER_BIT,				//	VkMemoryOutputFlags	outputMask;
+			VK_MEMORY_INPUT_HOST_READ_BIT,				//	VkMemoryInputFlags	inputMask;
+			queueFamilyIndex,							//	deUint32			srcQueueFamilyIndex;
+			queueFamilyIndex,							//	deUint32			destQueueFamilyIndex;
+			*readImageBuffer,							//	VkBuffer			buffer;
+			0u,											//	VkDeviceSize		offset;
+			imageSizeBytes								//	VkDeviceSize		size;
+		};
+		const void*				barriers[]				= { &copyFinishBarrier };
+		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	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(vertices),			//	VkDeviceSize	size;
+		};
+		void*						vertexBufPtr	= vertexBufferMemory->getHostPtr();
+
+		deMemcpy(vertexBufPtr, &vertices[0], sizeof(vertices));
+		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));
+
+		VK_CHECK(vk.queueSubmit(queue, 1u, &cmdBuf.get(), *fence));
+		VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
+	}
+
+	// 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;
+		};
+		void*						imagePtr	= readImageBufferMemory->getHostPtr();
+
+		VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
+		context.getTestContext().getLog() << TestLog::Image("Result", "Result", tcu::ConstPixelBufferAccess(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), renderSize.x(), renderSize.y(), 1, imagePtr));
+	}
+
+	return tcu::TestStatus::pass("Rendering succeeded");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createSmokeTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	smokeTests	(new tcu::TestCaseGroup(testCtx, "smoke", "Smoke Tests"));
+
+	addFunctionCase				(smokeTests.get(), "create_sampler",	"",	createSamplerTest);
+	addFunctionCaseWithPrograms	(smokeTests.get(), "create_shader",		"", createShaderProgs,		createShaderModuleTest);
+	addFunctionCaseWithPrograms	(smokeTests.get(), "triangle",			"", createTriangleProgs,	renderTriangleTest);
+	addFunctionCaseWithPrograms	(smokeTests.get(), "asm_triangle",		"", createTriangleAsmProgs,	renderTriangleTest);
+
+	return smokeTests.release();
+}
+
+} // api
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.hpp b/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.hpp
new file mode 100644
index 0000000..8184e7e
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiSmokeTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTAPISMOKETESTS_HPP
+#define _VKTAPISMOKETESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Simple Smoke Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+tcu::TestCaseGroup*		createSmokeTests		(tcu::TestContext& testCtx);
+
+} // api
+} // vkt
+
+#endif // _VKTAPISMOKETESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/api/vktApiTests.cpp b/external/vulkancts/modules/vulkan/api/vktApiTests.cpp
new file mode 100644
index 0000000..ab6ea5b
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiTests.cpp
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief API Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktApiTests.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include "vktApiSmokeTests.hpp"
+#include "vktApiDeviceInitializationTests.hpp"
+#include "vktApiObjectManagementTests.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	apiTests	(new tcu::TestCaseGroup(testCtx, "api", "API Tests"));
+
+	apiTests->addChild(createSmokeTests					(testCtx));
+	apiTests->addChild(createDeviceInitializationTests	(testCtx));
+	apiTests->addChild(createObjectManagementTests		(testCtx));
+
+	return apiTests.release();
+}
+
+} // api
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/api/vktApiTests.hpp b/external/vulkancts/modules/vulkan/api/vktApiTests.hpp
new file mode 100644
index 0000000..4bfc9cd
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/api/vktApiTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTAPITESTS_HPP
+#define _VKTAPITESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief API tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace api
+{
+
+tcu::TestCaseGroup*		createTests		(tcu::TestContext& testCtx);
+
+} // api
+} // vkt
+
+#endif // _VKTAPITESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/binding_model/CMakeLists.txt b/external/vulkancts/modules/vulkan/binding_model/CMakeLists.txt
new file mode 100644
index 0000000..fe3e727
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/binding_model/CMakeLists.txt
@@ -0,0 +1,18 @@
+# dEQP-VK.binding_model
+
+include_directories(..)
+
+set(DEQP_VK_BINDING_MODEL_SRCS
+	vktBindingModelTests.cpp
+	vktBindingModelTests.hpp
+	vktBindingShaderAccessTests.cpp
+	vktBindingShaderAccessTests.hpp
+	)
+
+set(DEQP_VK_BINDING_MODEL_LIBS
+	tcutil
+	vkutil
+	)
+
+add_library(deqp-vk-binding-model STATIC ${DEQP_VK_BINDING_MODEL_SRCS})
+target_link_libraries(deqp-vk-binding-model ${DEQP_VK_BINDING_MODEL_LIBS})
diff --git a/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.cpp b/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.cpp
new file mode 100644
index 0000000..fbc6049
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.cpp
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Binding Model tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktBindingModelTests.hpp"
+
+#include "vktBindingShaderAccessTests.hpp"
+
+#include "deUniquePtr.hpp"
+
+namespace vkt
+{
+namespace BindingModel
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "binding_model", "Resource binding tests"));
+
+	group->addChild(createShaderAccessTests(testCtx));
+
+	// \todo [2015-07-30 jarkko] .change_binding.{between_renderpasses, within_pass}
+	// \todo [2015-07-30 jarkko] .descriptor_set_chain
+	// \todo [2015-07-30 jarkko] .update_descriptor_set
+
+	return group.release();
+}
+
+} // BindingModel
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.hpp b/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.hpp
new file mode 100644
index 0000000..09e7b5b
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/binding_model/vktBindingModelTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTBINDINGMODELTESTS_HPP
+#define _VKTBINDINGMODELTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Binding Model tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace BindingModel
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx);
+
+} // BindingModel
+} // vkt
+
+#endif // _VKTBINDINGMODELTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.cpp b/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.cpp
new file mode 100644
index 0000000..ccbc898
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.cpp
@@ -0,0 +1,6469 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Binding shader access tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktBindingShaderAccessTests.hpp"
+
+#include "vktTestCase.hpp"
+
+#include "vkDefs.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkMemUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include "tcuVector.hpp"
+#include "tcuVectorUtil.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuResultCollector.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuRGBA.hpp"
+#include "tcuSurface.hpp"
+#include "tcuImageCompare.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deSharedPtr.hpp"
+#include "deStringUtil.hpp"
+#include "deArrayUtil.hpp"
+
+#include "qpInfo.h"
+
+namespace vkt
+{
+namespace BindingModel
+{
+namespace
+{
+
+enum ResourceFlag
+{
+	RESOURCE_FLAG_IMMUTABLE_SAMPLER = (1u << 0u),
+
+	RESOURCE_FLAG_LAST				= (1u << 1u)
+};
+
+static const char* const s_quadrantGenVertexPosSource =	"	highp int quadPhase = gl_VertexID % 6;\n"
+														"	highp int quadXcoord = int(quadPhase == 1 || quadPhase == 4 || quadPhase == 5);\n"
+														"	highp int quadYcoord = int(quadPhase == 2 || quadPhase == 3 || quadPhase == 5);\n"
+														"	highp int quadOriginX = (gl_VertexID / 6) % 2;\n"
+														"	highp int quadOriginY = (gl_VertexID / 6) / 2;\n"
+														"	quadrant_id = gl_VertexID / 6;\n"
+														"	result_position = vec4(float(quadOriginX + quadXcoord - 1), float(quadOriginY + quadYcoord - 1), 0.0, 1.0);\n";
+
+bool isUniformDescriptorType (vk::VkDescriptorType type)
+{
+	return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+		   type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+		   type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+}
+
+bool isDynamicDescriptorType (vk::VkDescriptorType type)
+{
+	return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || type == vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+}
+
+vk::VkFormat mapToVkTextureFormat (const tcu::TextureFormat& format)
+{
+	if (format == tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))
+		return vk::VK_FORMAT_R8G8B8A8_UNORM;
+
+	DE_FATAL("Not implemented");
+	return vk::VK_FORMAT_UNDEFINED;
+}
+
+vk::VkImageType viewTypeToImageType (vk::VkImageViewType type)
+{
+	switch (type)
+	{
+		case vk::VK_IMAGE_VIEW_TYPE_1D:
+		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return vk::VK_IMAGE_TYPE_1D;
+		case vk::VK_IMAGE_VIEW_TYPE_2D:
+		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return vk::VK_IMAGE_TYPE_2D;
+		case vk::VK_IMAGE_VIEW_TYPE_3D:			return vk::VK_IMAGE_TYPE_3D;
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return vk::VK_IMAGE_TYPE_2D;
+
+		default:
+			DE_FATAL("Impossible");
+			return (vk::VkImageType)0;
+	}
+}
+
+vk::VkTexFilter mapMagFilterToVkTexFilter (tcu::Sampler::FilterMode mode)
+{
+	switch (mode)
+	{
+		case tcu::Sampler::NEAREST:	return vk::VK_TEX_FILTER_NEAREST;
+		case tcu::Sampler::LINEAR:	return vk::VK_TEX_FILTER_LINEAR;
+
+		default:
+			DE_FATAL("Illegal filter mode");
+			return (vk::VkTexFilter)0;
+	}
+}
+
+vk::VkTexFilter mapMinFilterToVkTexFilter (tcu::Sampler::FilterMode mode)
+{
+	switch (mode)
+	{
+		case tcu::Sampler::NEAREST:					return vk::VK_TEX_FILTER_NEAREST;
+		case tcu::Sampler::LINEAR:					return vk::VK_TEX_FILTER_LINEAR;
+		case tcu::Sampler::NEAREST_MIPMAP_NEAREST:	return vk::VK_TEX_FILTER_NEAREST;
+		case tcu::Sampler::LINEAR_MIPMAP_NEAREST:	return vk::VK_TEX_FILTER_LINEAR;
+		case tcu::Sampler::NEAREST_MIPMAP_LINEAR:	return vk::VK_TEX_FILTER_NEAREST;
+		case tcu::Sampler::LINEAR_MIPMAP_LINEAR:	return vk::VK_TEX_FILTER_LINEAR;
+
+		default:
+			DE_FATAL("Illegal filter mode");
+			return (vk::VkTexFilter)0;
+	}
+}
+
+vk::VkTexMipmapMode mapMinFilterToVkTexMipmapMode (tcu::Sampler::FilterMode mode)
+{
+	switch (mode)
+	{
+		case tcu::Sampler::NEAREST:					return vk::VK_TEX_MIPMAP_MODE_BASE;
+		case tcu::Sampler::LINEAR:					return vk::VK_TEX_MIPMAP_MODE_BASE;
+		case tcu::Sampler::NEAREST_MIPMAP_NEAREST:	return vk::VK_TEX_MIPMAP_MODE_NEAREST;
+		case tcu::Sampler::LINEAR_MIPMAP_NEAREST:	return vk::VK_TEX_MIPMAP_MODE_NEAREST;
+		case tcu::Sampler::NEAREST_MIPMAP_LINEAR:	return vk::VK_TEX_MIPMAP_MODE_LINEAR;
+		case tcu::Sampler::LINEAR_MIPMAP_LINEAR:	return vk::VK_TEX_MIPMAP_MODE_LINEAR;
+
+		default:
+			DE_FATAL("Illegal filter mode");
+			return (vk::VkTexMipmapMode)0;
+	}
+}
+
+vk::VkTexAddressMode mapToVkTexAddressMode (tcu::Sampler::WrapMode mode)
+{
+	switch (mode)
+	{
+		case tcu::Sampler::CLAMP_TO_EDGE:		return vk::VK_TEX_ADDRESS_MODE_CLAMP;
+		case tcu::Sampler::CLAMP_TO_BORDER:		return vk::VK_TEX_ADDRESS_MODE_CLAMP_BORDER;
+		case tcu::Sampler::REPEAT_GL:			return vk::VK_TEX_ADDRESS_MODE_WRAP;
+		case tcu::Sampler::MIRRORED_REPEAT_GL:	return vk::VK_TEX_ADDRESS_MODE_MIRROR;
+
+		default:
+			DE_FATAL("Illegal wrap mode");
+			return (vk::VkTexAddressMode)0;
+	}
+}
+
+vk::VkCompareOp mapToVkCompareOp (tcu::Sampler::CompareMode mode)
+{
+	switch (mode)
+	{
+		case tcu::Sampler::COMPAREMODE_LESS:				return vk::VK_COMPARE_OP_LESS;
+		case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL:		return vk::VK_COMPARE_OP_LESS_EQUAL;
+		case tcu::Sampler::COMPAREMODE_GREATER:				return vk::VK_COMPARE_OP_GREATER;
+		case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL:	return vk::VK_COMPARE_OP_GREATER_EQUAL;
+		case tcu::Sampler::COMPAREMODE_EQUAL:				return vk::VK_COMPARE_OP_EQUAL;
+		case tcu::Sampler::COMPAREMODE_NOT_EQUAL:			return vk::VK_COMPARE_OP_NOT_EQUAL;
+		case tcu::Sampler::COMPAREMODE_ALWAYS:				return vk::VK_COMPARE_OP_ALWAYS;
+		case tcu::Sampler::COMPAREMODE_NEVER:				return vk::VK_COMPARE_OP_NEVER;
+
+		default:
+			DE_FATAL("Illegal compare mode");
+			return (vk::VkCompareOp)0;
+	}
+}
+
+deUint32 getTextureLevelPyramidDataSize (const tcu::TextureLevelPyramid& srcImage)
+{
+	deUint32 dataSize = 0;
+	for (int level = 0; level < srcImage.getNumLevels(); ++level)
+	{
+		const tcu::ConstPixelBufferAccess srcAccess = srcImage.getLevel(level);
+
+		// tightly packed
+		DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
+
+		dataSize += srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
+	}
+	return dataSize;
+}
+
+void writeTextureLevelPyramidData (void* dst, deUint32 dstLen, const tcu::TextureLevelPyramid& srcImage, vk::VkImageViewType viewType, std::vector<vk::VkBufferImageCopy>* copySlices)
+{
+	// \note cube is copied face-by-face
+	const deUint32	arraySize	= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (srcImage.getLevel(0).getHeight()) :
+								  (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (srcImage.getLevel(0).getDepth()) :
+								  (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)														? (1) :
+								  (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (srcImage.getLevel(0).getDepth()) :
+								  ((deUint32)0);
+	deUint32		levelOffset	= 0;
+
+	DE_ASSERT(arraySize != 0);
+
+	for (int level = 0; level < srcImage.getNumLevels(); ++level)
+	{
+		const tcu::ConstPixelBufferAccess	srcAccess		= srcImage.getLevel(level);
+		const tcu::PixelBufferAccess		dstAccess		(srcAccess.getFormat(), srcAccess.getSize(), srcAccess.getPitch(), (deUint8*)dst + levelOffset);
+		const deUint32						dataSize		= srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
+		const deUint32						sliceDataSize	= dataSize / arraySize;
+		const deInt32						sliceHeight		= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1) : (srcAccess.getHeight());
+		const deInt32						sliceDepth		= (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (srcAccess.getDepth()) : (1);
+		const tcu::IVec3					sliceSize		(srcAccess.getWidth(), sliceHeight, sliceDepth);
+
+		// tightly packed
+		DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
+
+		for (int sliceNdx = 0; sliceNdx < (int)arraySize; ++sliceNdx)
+		{
+			const vk::VkBufferImageCopy copySlice =
+			{
+				(vk::VkDeviceSize)levelOffset + sliceNdx * sliceDataSize,	// bufferOffset
+				(deUint32)sliceSize.x(),									// bufferRowLength
+				(deUint32)sliceSize.y(),									// bufferImageHeight
+				{
+					vk::VK_IMAGE_ASPECT_COLOR,			// aspect
+					(deUint32)level,					// mipLevel
+					(deUint32)sliceNdx,					// arrayLayer
+					1u,									// arraySize
+				},															// imageSubresource
+				{
+					0,
+					0,
+					0,
+				},															// imageOffset
+				{
+					sliceSize.x(),
+					sliceSize.y(),
+					sliceSize.z(),
+				}															// imageExtent
+			};
+			copySlices->push_back(copySlice);
+		}
+
+		DE_ASSERT(arraySize * sliceDataSize == dataSize);
+
+		tcu::copy(dstAccess, srcAccess);
+		levelOffset += dataSize;
+	}
+
+	DE_ASSERT(dstLen == levelOffset);
+	DE_UNREF(dstLen);
+}
+
+de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkBuffer buffer, vk::MemoryRequirement requirement)
+{
+	const vk::VkMemoryRequirements	requirements	= vk::getBufferMemoryRequirements(vki, device, buffer);
+	de::MovePtr<vk::Allocation>		allocation		= allocator.allocate(requirements, requirement);
+
+	VK_CHECK(vki.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset()));
+	return allocation;
+}
+
+de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkImage image, vk::MemoryRequirement requirement)
+{
+	const vk::VkMemoryRequirements	requirements	= vk::getImageMemoryRequirements(vki, device, image);
+	de::MovePtr<vk::Allocation>		allocation		= allocator.allocate(requirements, requirement);
+
+	VK_CHECK(vki.bindImageMemory(device, image, allocation->getMemory(), allocation->getOffset()));
+	return allocation;
+}
+
+vk::VkDescriptorInfo createDescriptorInfo (vk::VkBuffer buffer, vk::VkDeviceSize offset, vk::VkDeviceSize range)
+{
+	const vk::VkDescriptorInfo resultInfo =
+	{
+		0,							// bufferView
+		0,							// sampler
+		0,							// imageView
+		(vk::VkImageLayout)0,		// imageLayout
+		{ buffer, offset, range }	// bufferInfo
+	};
+	return resultInfo;
+}
+
+vk::VkDescriptorInfo createDescriptorInfo (vk::VkBufferView bufferView)
+{
+	const vk::VkDescriptorInfo resultInfo =
+	{
+		bufferView,					// bufferView
+		0,							// sampler
+		0,							// imageView
+		(vk::VkImageLayout)0,		// imageLayout
+		{ (vk::VkBuffer)0, 0, 0 }	// bufferInfo
+	};
+	return resultInfo;
+}
+
+vk::VkDescriptorInfo createDescriptorInfo (vk::VkSampler sampler)
+{
+	const vk::VkDescriptorInfo resultInfo =
+	{
+		0,							// bufferView
+		sampler,					// sampler
+		0,							// imageView
+		(vk::VkImageLayout)0,		// imageLayout
+		{ (vk::VkBuffer)0, 0, 0 }	// bufferInfo
+	};
+	return resultInfo;
+}
+
+vk::VkDescriptorInfo createDescriptorInfo (vk::VkImageView imageView, vk::VkImageLayout layout)
+{
+	const vk::VkDescriptorInfo resultInfo =
+	{
+		0,							// bufferView
+		0,							// sampler
+		imageView,					// imageView
+		layout,						// imageLayout
+		{ (vk::VkBuffer)0, 0, 0 }	// bufferInfo
+	};
+	return resultInfo;
+}
+
+vk::VkDescriptorInfo createDescriptorInfo (vk::VkSampler sampler, vk::VkImageView imageView, vk::VkImageLayout layout)
+{
+	const vk::VkDescriptorInfo resultInfo =
+	{
+		0,							// bufferView
+		sampler,					// sampler
+		imageView,					// imageView
+		layout,						// imageLayout
+		{ (vk::VkBuffer)0, 0, 0 }	// bufferInfo
+	};
+	return resultInfo;
+}
+
+vk::VkClearValue createClearValueColor (const tcu::Vec4& color)
+{
+	vk::VkClearValue retVal;
+
+	retVal.color.float32[0] = color.x();
+	retVal.color.float32[1] = color.y();
+	retVal.color.float32[2] = color.z();
+	retVal.color.float32[3] = color.w();
+
+	return retVal;
+};
+
+void drawQuadrantReferenceResult (const tcu::PixelBufferAccess& dst, const tcu::Vec4& c1, const tcu::Vec4& c2, const tcu::Vec4& c3, const tcu::Vec4& c4)
+{
+	tcu::clear(tcu::getSubregion(dst, 0,					0,						dst.getWidth() / 2,						dst.getHeight() / 2),					c1);
+	tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2,	0,						dst.getWidth() - dst.getWidth() / 2,	dst.getHeight() / 2),					c2);
+	tcu::clear(tcu::getSubregion(dst, 0,					dst.getHeight() / 2,	dst.getWidth() / 2,						dst.getHeight() - dst.getHeight() / 2),	c3);
+	tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2,	dst.getHeight() / 2,	dst.getWidth() - dst.getWidth() / 2,	dst.getHeight() - dst.getHeight() / 2),	c4);
+}
+
+class SingleTargetRenderInstance : public vkt::TestInstance
+{
+public:
+											SingleTargetRenderInstance	(Context&			context,
+																		 const tcu::UVec2&	size);
+
+private:
+	static vk::Move<vk::VkImage>			createColorAttachment		(const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 vk::Allocator&					allocator,
+																		 const tcu::TextureFormat&		format,
+																		 const tcu::UVec2&				size,
+																		 de::MovePtr<vk::Allocation>*	outAllocation);
+
+	static vk::Move<vk::VkImageView>		createColorAttachmentView	(const vk::DeviceInterface&	vki,
+																		 vk::VkDevice				device,
+																		 const tcu::TextureFormat&	format,
+																		 vk::VkImage				image);
+
+	static vk::Move<vk::VkRenderPass>		createRenderPass			(const vk::DeviceInterface&	vki,
+																		 vk::VkDevice				device,
+																		 const tcu::TextureFormat&	format);
+
+	static vk::Move<vk::VkFramebuffer>		createFramebuffer			(const vk::DeviceInterface&	vki,
+																		 vk::VkDevice				device,
+																		 vk::VkRenderPass			renderpass,
+																		 vk::VkImageView			colorAttachmentView,
+																		 const tcu::UVec2&			size);
+
+	static vk::Move<vk::VkCmdPool>			createCommandPool			(const vk::DeviceInterface&	vki,
+																		 vk::VkDevice				device,
+																		 deUint32					queueFamilyIndex);
+
+	virtual void							logTestPlan					(void) const = 0;
+	virtual void							renderToTarget				(void) = 0;
+	virtual tcu::TestStatus					verifyResultImage			(const tcu::ConstPixelBufferAccess& result) const = 0;
+
+	void									readRenderTarget			(tcu::TextureLevel& dst);
+	tcu::TestStatus							iterate						(void);
+
+protected:
+	const tcu::TextureFormat				m_targetFormat;
+	const tcu::UVec2						m_targetSize;
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+	const vk::VkQueue						m_queue;
+	const deUint32							m_queueFamilyIndex;
+	vk::Allocator&							m_allocator;
+	de::MovePtr<vk::Allocation>				m_colorAttachmentMemory;
+	const vk::Unique<vk::VkImage>			m_colorAttachmentImage;
+	const vk::Unique<vk::VkImageView>		m_colorAttachmentView;
+	const vk::Unique<vk::VkRenderPass>		m_renderPass;
+	const vk::Unique<vk::VkFramebuffer>		m_framebuffer;
+	const vk::Unique<vk::VkCmdPool>			m_cmdPool;
+
+	bool									m_firstIteration;
+};
+
+SingleTargetRenderInstance::SingleTargetRenderInstance (Context&			context,
+														const tcu::UVec2&	size)
+	: vkt::TestInstance			(context)
+	, m_targetFormat			(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
+	, m_targetSize				(size)
+	, m_vki						(context.getDeviceInterface())
+	, m_device					(context.getDevice())
+	, m_queue					(context.getUniversalQueue())
+	, m_queueFamilyIndex		(context.getUniversalQueueFamilyIndex())
+	, m_allocator				(context.getDefaultAllocator())
+	, m_colorAttachmentMemory	(DE_NULL)
+	, m_colorAttachmentImage	(createColorAttachment(m_vki, m_device, m_allocator, m_targetFormat, m_targetSize, &m_colorAttachmentMemory))
+	, m_colorAttachmentView		(createColorAttachmentView(m_vki, m_device, m_targetFormat, *m_colorAttachmentImage))
+	, m_renderPass				(createRenderPass(m_vki, m_device, m_targetFormat))
+	, m_framebuffer				(createFramebuffer(m_vki, m_device, *m_renderPass, *m_colorAttachmentView, m_targetSize))
+	, m_cmdPool					(createCommandPool(m_vki, m_device, context.getUniversalQueueFamilyIndex()))
+	, m_firstIteration			(true)
+{
+}
+
+vk::Move<vk::VkImage> SingleTargetRenderInstance::createColorAttachment (const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 vk::Allocator&					allocator,
+																		 const tcu::TextureFormat&		format,
+																		 const tcu::UVec2&				size,
+																		 de::MovePtr<vk::Allocation>*	outAllocation)
+{
+	const vk::VkImageCreateInfo	imageInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+		DE_NULL,
+		vk::VK_IMAGE_TYPE_2D,							// imageType
+		mapToVkTextureFormat(format),					// format
+		{ (deInt32)size.x(), (deInt32)size.y(), 1 },	// extent
+		1,												// mipLevels
+		1,												// arraySize
+		1,												// samples
+		vk::VK_IMAGE_TILING_OPTIMAL,					// tiling
+		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	// usage
+		0,												// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,					// sharingMode
+		0u,												// queueFamilyCount
+		DE_NULL,										// pQueueFamilyIndices
+		vk::VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
+	};
+
+	vk::Move<vk::VkImage>		image		(vk::createImage(vki, device, &imageInfo));
+	de::MovePtr<vk::Allocation>	allocation	(allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any));
+
+	*outAllocation = allocation;
+	return image;
+}
+
+vk::Move<vk::VkImageView> SingleTargetRenderInstance::createColorAttachmentView (const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 const tcu::TextureFormat&	format,
+																				 vk::VkImage				image)
+{
+	const vk::VkImageViewCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+		DE_NULL,
+		image,							// image
+		vk::VK_IMAGE_VIEW_TYPE_2D,		// viewType
+		mapToVkTextureFormat(format),	// format
+		{ vk::VK_CHANNEL_SWIZZLE_R, vk::VK_CHANNEL_SWIZZLE_G, vk::VK_CHANNEL_SWIZZLE_B, vk::VK_CHANNEL_SWIZZLE_A },
+		{
+			vk::VK_IMAGE_ASPECT_COLOR_BIT,	// aspectMask
+			0u,								// baseMipLevel
+			1u,								// mipLevels
+			0u,								// baseArrayLayer
+			1u,								// arraySize
+		},
+		0u,								// flags
+	};
+
+	return vk::createImageView(vki, device, &createInfo);
+}
+
+vk::Move<vk::VkRenderPass> SingleTargetRenderInstance::createRenderPass (const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 const tcu::TextureFormat&		format)
+{
+	const vk::VkAttachmentDescription	attachmentDescription	=
+	{
+		vk::VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,
+		DE_NULL,
+		mapToVkTextureFormat(format),					// format
+		1u,												// samples
+		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				// loadOp
+		vk::VK_ATTACHMENT_STORE_OP_STORE,				// storeOp
+		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
+		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// initialLayout
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// finalLayout
+		0u,												// flags
+	};
+	const vk::VkAttachmentReference		colorAttachment			=
+	{
+		0u,												// attachment
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// layout
+	};
+	const vk::VkAttachmentReference		depthStencilAttachment	=
+	{
+		vk::VK_NO_ATTACHMENT,							// attachment
+		vk::VK_IMAGE_LAYOUT_UNDEFINED					// layout
+	};
+	const vk::VkSubpassDescription		subpass					=
+	{
+		vk::VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,
+		DE_NULL,
+		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,			// pipelineBindPoint
+		0u,												// flags
+		0u,												// inputCount
+		DE_NULL,										// inputAttachments
+		1u,												// colorCount
+		&colorAttachment,								// pColorAttachments
+		DE_NULL,										// pResolveAttachments
+		depthStencilAttachment,							// depthStencilAttachment
+		0u,												// preserveCount
+		DE_NULL											// pPreserveAttachments
+	};
+	const vk::VkRenderPassCreateInfo	renderPassCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+		DE_NULL,
+		1u,												// attachmentCount
+		&attachmentDescription,							// pAttachments
+		1u,												// subpassCount
+		&subpass,										// pSubpasses
+		0u,												// dependencyCount
+		DE_NULL,										// pDependencies
+	};
+
+	return vk::createRenderPass(vki, device, &renderPassCreateInfo);
+}
+
+vk::Move<vk::VkFramebuffer> SingleTargetRenderInstance::createFramebuffer (const vk::DeviceInterface&	vki,
+																		   vk::VkDevice					device,
+																		   vk::VkRenderPass				renderpass,
+																		   vk::VkImageView				colorAttachmentView,
+																		   const tcu::UVec2&			size)
+{
+	const vk::VkFramebufferCreateInfo	framebufferCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+		DE_NULL,
+		renderpass,				// renderPass
+		1u,						// attachmentCount
+		&colorAttachmentView,	// pAttachments
+		size.x(),				// width
+		size.y(),				// height
+		1,						// layers
+	};
+
+	return vk::createFramebuffer(vki, device, &framebufferCreateInfo);
+}
+
+vk::Move<vk::VkCmdPool> SingleTargetRenderInstance::createCommandPool (const vk::DeviceInterface&	vki,
+																	   vk::VkDevice					device,
+																	   deUint32						queueFamilyIndex)
+{
+	const vk::VkCmdPoolCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
+		DE_NULL,
+		queueFamilyIndex,						// queueFamilyIndex
+		vk::VK_CMD_POOL_CREATE_TRANSIENT_BIT,	// flags
+	};
+	return vk::createCommandPool(vki, device, &createInfo);
+}
+
+void SingleTargetRenderInstance::readRenderTarget (tcu::TextureLevel& dst)
+{
+	const deUint64						pixelDataSize				= (deUint64)(m_targetSize.x() * m_targetSize.y() * m_targetFormat.getPixelSize());
+	const vk::VkBufferCreateInfo		bufferCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		pixelDataSize,									// size
+		vk::VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,	// usage
+		0u,												// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,					// sharingMode
+		0u,												// queueFamilyCount
+		DE_NULL,										// pQueueFamilyIndices
+	};
+	const vk::Unique<vk::VkBuffer>		buffer						(vk::createBuffer(m_vki, m_device, &bufferCreateInfo));
+	const vk::VkImageSubresourceRange	fullSubrange				=
+	{
+		vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
+		0u,												// baseMipLevel
+		1u,												// mipLevels
+		0u,												// baseArraySlice
+		1u,												// arraySize
+	};
+	const vk::VkImageMemoryBarrier		imageBarrier				=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,		// outputMask
+		vk::VK_MEMORY_INPUT_TRANSFER_BIT,				// inputMask
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// oldLayout
+		vk::VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,	// newLayout
+		vk::VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
+		*m_colorAttachmentImage,						// image
+		fullSubrange,									// subresourceRange
+	};
+	const vk::VkBufferMemoryBarrier		memoryBarrier				=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_TRANSFER_BIT,				// outputMask
+		vk::VK_MEMORY_INPUT_HOST_READ_BIT,				// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
+		*buffer,										// buffer
+		0u,												// offset
+		(vk::VkDeviceSize)pixelDataSize					// size
+	};
+	const vk::VkCmdBufferCreateInfo		cmdBufCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		*m_cmdPool,							// cmdPool
+		vk::VK_CMD_BUFFER_LEVEL_PRIMARY,	// level
+		0u,									// flags
+	};
+	const vk::VkFenceCreateInfo			fenceCreateInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+		DE_NULL,
+		0u,												// flags
+	};
+	const vk::VkCmdBufferBeginInfo		cmdBufBeginInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(vk::VkRenderPass)0u,																			// renderPass
+		0u,																								// subpass
+		(vk::VkFramebuffer)0u,																			// framebuffer
+	};
+	const vk::VkImageSubresourceCopy	firstSlice					=
+	{
+		vk::VK_IMAGE_ASPECT_COLOR,						// aspect
+		0,												// mipLevel
+		0,												// arrayLayer
+		1,												// arraySize
+	};
+	const vk::VkBufferImageCopy			copyRegion					=
+	{
+		0u,												// bufferOffset
+		m_targetSize.x(),								// bufferRowLength
+		m_targetSize.y(),								// bufferImageHeight
+		firstSlice,										// imageSubresource
+		{ 0, 0, 0 },									// imageOffset
+		{ (deInt32)m_targetSize.x(), (deInt32)m_targetSize.y(), 1 }		// imageExtent
+	};
+
+	const de::MovePtr<vk::Allocation>	bufferMemory				= allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible);
+
+	const vk::Unique<vk::VkCmdBuffer>	cmd							(vk::createCommandBuffer(m_vki, m_device, &cmdBufCreateInfo));
+	const vk::Unique<vk::VkFence>		cmdCompleteFence			(vk::createFence(m_vki, m_device, &fenceCreateInfo));
+	const void* const					imageBarrierPtr				= &imageBarrier;
+	const void* const					bufferBarrierPtr			= &memoryBarrier;
+	const deUint64						infiniteTimeout				= ~(deUint64)0u;
+
+	// copy content to buffer
+	VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
+	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_FALSE, 1, &imageBarrierPtr);
+	m_vki.cmdCopyImageToBuffer(*cmd, *m_colorAttachmentImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, *buffer, 1, &copyRegion);
+	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_FALSE, 1, &bufferBarrierPtr);
+	VK_CHECK(m_vki.endCommandBuffer(*cmd));
+
+	// wait for transfer to complete
+	VK_CHECK(m_vki.queueSubmit(m_queue, 1, &cmd.get(), *cmdCompleteFence));
+	VK_CHECK(m_vki.waitForFences(m_device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
+
+	dst.setStorage(m_targetFormat, m_targetSize.x(), m_targetSize.y());
+
+	// copy data
+	invalidateMappedMemoryRange(m_vki, m_device, bufferMemory->getMemory(), bufferMemory->getOffset(), pixelDataSize);
+	tcu::copy(dst, tcu::ConstPixelBufferAccess(dst.getFormat(), dst.getSize(), bufferMemory->getHostPtr()));
+}
+
+tcu::TestStatus SingleTargetRenderInstance::iterate (void)
+{
+	tcu::TextureLevel resultImage;
+
+	// log
+	if (m_firstIteration)
+	{
+		logTestPlan();
+		m_firstIteration = false;
+	}
+
+	// render
+	{
+		// transition to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+		const vk::VkImageSubresourceRange	fullSubrange				=
+		{
+			vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
+			0u,												// baseMipLevel
+			1u,												// mipLevels
+			0u,												// baseArraySlice
+			1u,												// arraySize
+		};
+		const vk::VkImageMemoryBarrier		imageBarrier				=
+		{
+			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+			DE_NULL,
+			0u,												// outputMask
+			vk::VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT,		// inputMask
+			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// oldLayout
+			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// newLayout
+			vk::VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
+			vk::VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
+			*m_colorAttachmentImage,						// image
+			fullSubrange,									// subresourceRange
+		};
+		const vk::VkCmdBufferCreateInfo		cmdBufCreateInfo			=
+		{
+			vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+			DE_NULL,
+			*m_cmdPool,										// cmdPool
+			vk::VK_CMD_BUFFER_LEVEL_PRIMARY,				// level
+			0u,												// flags
+		};
+		const vk::VkCmdBufferBeginInfo		cmdBufBeginInfo				=
+		{
+			vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+			DE_NULL,
+			vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+			(vk::VkRenderPass)0u,																			// renderPass
+			0u,																								// subpass
+			(vk::VkFramebuffer)0u,																			// framebuffer
+		};
+
+		const vk::Unique<vk::VkCmdBuffer>	cmd					(vk::createCommandBuffer(m_vki, m_device, &cmdBufCreateInfo));
+		const void* const					imageBarrierPtr		= &imageBarrier;
+
+		VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
+		m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_FALSE, 1, &imageBarrierPtr);
+		VK_CHECK(m_vki.endCommandBuffer(*cmd));
+		VK_CHECK(m_vki.queueSubmit(m_queue, 1, &cmd.get(), 0));
+
+		// and then render to
+		renderToTarget();
+	}
+
+	// read and verify
+	readRenderTarget(resultImage);
+	return verifyResultImage(resultImage.getAccess());
+}
+
+class RenderInstanceShaders
+{
+public:
+														RenderInstanceShaders		(const vk::DeviceInterface&		vki,
+																					 vk::VkDevice					device,
+																					 const vk::BinaryCollection&	programCollection);
+
+	inline bool											hasTessellationStage		(void) const { return *m_tessCtrlShader != 0 || *m_tessEvalShader != 0;	}
+	inline deUint32										getNumStages				(void) const { return (deUint32)m_stageInfos.size();					}
+	inline const vk::VkPipelineShaderStageCreateInfo*	getStages					(void) const { return &m_stageInfos[0];									}
+
+private:
+	void												addStage					(const vk::DeviceInterface&		vki,
+																					 vk::VkDevice					device,
+																					 const vk::BinaryCollection&	programCollection,
+																					 const char*					name,
+																					 vk::VkShaderStage				stage,
+																					 vk::Move<vk::VkShaderModule>*	outModule,
+																					 vk::Move<vk::VkShader>*		outShader);
+
+	vk::VkPipelineShaderStageCreateInfo					getShaderStageCreateInfo	(vk::VkShaderStage stage, vk::VkShader shader) const;
+
+	vk::Move<vk::VkShaderModule>						m_vertexShaderModule;
+	vk::Move<vk::VkShader>								m_vertexShader;
+	vk::Move<vk::VkShaderModule>						m_tessCtrlShaderModule;
+	vk::Move<vk::VkShader>								m_tessCtrlShader;
+	vk::Move<vk::VkShaderModule>						m_tessEvalShaderModule;
+	vk::Move<vk::VkShader>								m_tessEvalShader;
+	vk::Move<vk::VkShaderModule>						m_geometryShaderModule;
+	vk::Move<vk::VkShader>								m_geometryShader;
+	vk::Move<vk::VkShaderModule>						m_fragmentShaderModule;
+	vk::Move<vk::VkShader>								m_fragmentShader;
+	std::vector<vk::VkPipelineShaderStageCreateInfo>	m_stageInfos;
+};
+
+RenderInstanceShaders::RenderInstanceShaders (const vk::DeviceInterface&	vki,
+											  vk::VkDevice					device,
+											  const vk::BinaryCollection&	programCollection)
+{
+	addStage(vki, device, programCollection, "vertex",		vk::VK_SHADER_STAGE_VERTEX,				&m_vertexShaderModule,		&m_vertexShader);
+	addStage(vki, device, programCollection, "tess_ctrl",	vk::VK_SHADER_STAGE_TESS_CONTROL,		&m_tessCtrlShaderModule,	&m_tessCtrlShader);
+	addStage(vki, device, programCollection, "tess_eval",	vk::VK_SHADER_STAGE_TESS_EVALUATION,	&m_tessEvalShaderModule,	&m_tessEvalShader);
+	addStage(vki, device, programCollection, "geometry",	vk::VK_SHADER_STAGE_GEOMETRY,			&m_geometryShaderModule,	&m_geometryShader);
+	addStage(vki, device, programCollection, "fragment",	vk::VK_SHADER_STAGE_FRAGMENT,			&m_fragmentShaderModule,	&m_fragmentShader);
+
+	DE_ASSERT(!m_stageInfos.empty());
+}
+
+void RenderInstanceShaders::addStage (const vk::DeviceInterface&		vki,
+									  vk::VkDevice						device,
+									  const vk::BinaryCollection&		programCollection,
+									  const char*						name,
+									  vk::VkShaderStage					stage,
+									  vk::Move<vk::VkShaderModule>*		outModule,
+									  vk::Move<vk::VkShader>*			outShader)
+{
+	if (programCollection.contains(name))
+	{
+		vk::Move<vk::VkShaderModule>	module		= createShaderModule(vki, device, programCollection.get(name), (vk::VkShaderModuleCreateFlags)0);
+		const vk::VkShaderCreateInfo	createInfo	=
+		{
+			vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,
+			DE_NULL,
+			*module,		// module
+			"main",			// pName
+			0u,				// flags
+			stage
+		};
+		vk::Move<vk::VkShader>			shader		= vk::createShader(vki, device, &createInfo);
+
+		m_stageInfos.push_back(getShaderStageCreateInfo(stage, *shader));
+		*outModule = module;
+		*outShader = shader;
+	}
+}
+
+vk::VkPipelineShaderStageCreateInfo RenderInstanceShaders::getShaderStageCreateInfo (vk::VkShaderStage stage, vk::VkShader shader) const
+{
+	const vk::VkPipelineShaderStageCreateInfo	stageCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+		DE_NULL,
+		stage,			// stage
+		shader,			// shader
+		DE_NULL,		// pSpecializationInfo
+	};
+	return stageCreateInfo;
+}
+
+class SingleCmdRenderInstance : public SingleTargetRenderInstance
+{
+public:
+									SingleCmdRenderInstance	(Context&			context,
+															 bool				isPrimaryCmdBuf,
+															 const tcu::UVec2&	renderSize);
+
+private:
+	vk::Move<vk::VkPipeline>		createPipeline				(vk::VkPipelineLayout pipelineLayout);
+
+	virtual vk::VkPipelineLayout	getPipelineLayout			(void) const = 0;
+	virtual void					writeDrawCmdBuffer			(vk::VkCmdBuffer cmd) const = 0;
+
+	void							renderToTarget				(void);
+
+	const bool						m_isPrimaryCmdBuf;
+};
+
+SingleCmdRenderInstance::SingleCmdRenderInstance (Context&			context,
+												  bool				isPrimaryCmdBuf,
+												  const tcu::UVec2&	renderSize)
+	: SingleTargetRenderInstance	(context, renderSize)
+	, m_isPrimaryCmdBuf				(isPrimaryCmdBuf)
+{
+}
+
+vk::Move<vk::VkPipeline> SingleCmdRenderInstance::createPipeline (vk::VkPipelineLayout pipelineLayout)
+{
+	const RenderInstanceShaders							shaderStages		(m_vki, m_device, m_context.getBinaryCollection());
+	const vk::VkPrimitiveTopology						topology			= shaderStages.hasTessellationStage() ? vk::VK_PRIMITIVE_TOPOLOGY_PATCH : vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+	const vk::VkPipelineVertexInputStateCreateInfo		vertexInputState	=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+		DE_NULL,
+		0u,											// bindingCount
+		DE_NULL,									// pVertexBindingDescriptions
+		0u,											// attributeCount
+		DE_NULL,									// pVertexAttributeDescriptions
+	};
+	const vk::VkPipelineInputAssemblyStateCreateInfo	iaState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+		DE_NULL,
+		topology,									// topology
+		vk::VK_FALSE,								// primitiveRestartEnable
+	};
+	const vk::VkPipelineTessellationStateCreateInfo		tessState			=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
+		DE_NULL,
+		3u,											// patchControlPoints
+	};
+	const vk::VkViewport								viewport			=
+	{
+		0.0f,										// originX
+		0.0f,										// originY
+		float(m_targetSize.x()),					// width
+		float(m_targetSize.y()),					// height
+		0.0f,										// minDepth
+		1.0f,										// maxDepth
+	};
+	const vk::VkRect2D									renderArea			=
+	{
+		{ 0, 0 },													// offset
+		{ (deInt32)m_targetSize.x(), (deInt32)m_targetSize.y() },	// extent
+	};
+	const vk::VkPipelineViewportStateCreateInfo			vpState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+		DE_NULL,
+		1u,											// viewportCount
+		&viewport,
+		1u,
+		&renderArea,
+	};
+	const vk::VkPipelineRasterStateCreateInfo			rsState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,
+		DE_NULL,
+		vk::VK_TRUE,								// depthClipEnable
+		vk::VK_FALSE,								// rasterizerDiscardEnable
+		vk::VK_FILL_MODE_SOLID,						// fillMode
+		vk::VK_CULL_MODE_NONE,						// cullMode
+		vk::VK_FRONT_FACE_CCW,						// frontFace
+		vk::VK_FALSE,								// depthBiasEnable
+		0.0f,										// depthBias
+		0.0f,										// depthBiasClamp
+		0.0f,										// slopeScaledDepthBias
+		1.0f,										// lineWidth
+	};
+	const vk::VkSampleMask								sampleMask			= 0x01u;
+	const vk::VkPipelineMultisampleStateCreateInfo		msState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+		DE_NULL,
+		1u,											// rasterSamples
+		vk::VK_FALSE,								// sampleShadingEnable
+		0.0f,										// minSampleShading
+		&sampleMask									// sampleMask
+	};
+	const vk::VkPipelineDepthStencilStateCreateInfo		dsState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+		DE_NULL,
+		vk::VK_FALSE,								// depthTestEnable
+		vk::VK_FALSE,								// depthWriteEnable
+		vk::VK_COMPARE_OP_ALWAYS,					// depthCompareOp
+		vk::VK_FALSE,								// depthBoundsTestEnable
+		vk::VK_FALSE,								// stencilTestEnable
+		{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },	// front
+		{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },	// back
+		-1.0f,										// minDepthBounds
+		+1.0f,										// maxDepthBounds
+	};
+	const vk::VkPipelineColorBlendAttachmentState		cbAttachment		=
+	{
+		vk::VK_FALSE,								// blendEnable
+		vk::VK_BLEND_ZERO,							// srcBlendColor
+		vk::VK_BLEND_ZERO,							// destBlendColor
+		vk::VK_BLEND_OP_ADD,						// blendOpColor
+		vk::VK_BLEND_ZERO,							// srcBlendAlpha
+		vk::VK_BLEND_ZERO,							// destBlendAlpha
+		vk::VK_BLEND_OP_ADD,						// blendOpAlpha
+		vk::VK_CHANNEL_R_BIT | vk::VK_CHANNEL_G_BIT | vk::VK_CHANNEL_B_BIT | vk::VK_CHANNEL_A_BIT,	// channelWriteMask
+	};
+	const vk::VkPipelineColorBlendStateCreateInfo		cbState				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+		DE_NULL,
+		vk::VK_FALSE,								// alphaToCoverageEnable
+		vk::VK_FALSE,								// alphaToOneEnable
+		vk::VK_FALSE,								// logicOpEnable
+		vk::VK_LOGIC_OP_CLEAR,						// logicOp
+		1u,											// attachmentCount
+		&cbAttachment,								// pAttachments
+		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConst
+	};
+	const vk::VkPipelineDynamicStateCreateInfo			dynState			=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+		DE_NULL,
+		0u,											// dynamicStateCount
+		DE_NULL,									// pDynamicStates
+	};
+	const vk::VkGraphicsPipelineCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+		DE_NULL,
+		shaderStages.getNumStages(),									// stageCount
+		shaderStages.getStages(),										// pStages
+		&vertexInputState,												// pVertexInputState
+		&iaState,														// pInputAssemblyState
+		(shaderStages.hasTessellationStage() ? &tessState : DE_NULL),	// pTessellationState
+		&vpState,														// pViewportState
+		&rsState,														// pRasterState
+		&msState,														// pMultisampleState
+		&dsState,														// pDepthStencilState
+		&cbState,														// pColorBlendState
+		&dynState,														// pDynamicState
+		0u,																// flags
+		pipelineLayout,													// layout
+		*m_renderPass,													// renderPass
+		0u,																// subpass
+		(vk::VkPipeline)0,												// basePipelineHandle
+		0u,																// basePipelineIndex
+	};
+	return createGraphicsPipeline(m_vki, m_device, (vk::VkPipelineCache)0u, &createInfo);
+}
+
+void SingleCmdRenderInstance::renderToTarget (void)
+{
+	const vk::VkRect2D									renderArea					=
+	{
+		{ 0, 0 },													// offset
+		{ (deInt32)m_targetSize.x(), (deInt32)m_targetSize.y() },	// extent
+	};
+	const vk::VkCmdBufferCreateInfo						mainCmdBufCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		*m_cmdPool,							// cmdPool
+		vk::VK_CMD_BUFFER_LEVEL_PRIMARY,	// level
+		0u,									// flags
+	};
+	const vk::VkCmdBufferBeginInfo						mainCmdBufBeginInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(vk::VkRenderPass)0u,																			// renderPass
+		0u,																								// subpass
+		(vk::VkFramebuffer)0u,																			// framebuffer
+	};
+	const vk::VkCmdBufferCreateInfo						passCmdBufCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		*m_cmdPool,							// cmdPool
+		vk::VK_CMD_BUFFER_LEVEL_SECONDARY,	// level
+		0u,									// flags
+	};
+	const vk::VkCmdBufferBeginInfo						passCmdBufBeginInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(vk::VkRenderPass)*m_renderPass,																// renderPass
+		0u,																								// subpass
+		(vk::VkFramebuffer)*m_framebuffer,																// framebuffer
+	};
+	const vk::VkFenceCreateInfo							fenceCreateInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+		DE_NULL,
+		0u,			// flags
+	};
+	const vk::VkClearValue								clearValue					= createClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+	const vk::VkRenderPassBeginInfo						renderPassBeginInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+		DE_NULL,
+		*m_renderPass,		// renderPass
+		*m_framebuffer,		// framebuffer
+		renderArea,			// renderArea
+		1u,					// clearValueCount
+		&clearValue,		// pClearValues
+	};
+
+	const vk::VkPipelineLayout							pipelineLayout				(getPipelineLayout());
+	const vk::Unique<vk::VkPipeline>					pipeline					(createPipeline(pipelineLayout));
+	const vk::Unique<vk::VkCmdBuffer>					mainCmd						(vk::createCommandBuffer(m_vki, m_device, &mainCmdBufCreateInfo));
+	const vk::Unique<vk::VkCmdBuffer>					passCmd						((m_isPrimaryCmdBuf) ? (vk::Move<vk::VkCmdBuffer>()) : (vk::createCommandBuffer(m_vki, m_device, &passCmdBufCreateInfo)));
+	const vk::Unique<vk::VkFence>						fence						(vk::createFence(m_vki, m_device, &fenceCreateInfo));
+	const deUint64										infiniteTimeout				= ~(deUint64)0u;
+	const vk::VkRenderPassContents						passContents				= (m_isPrimaryCmdBuf) ? (vk::VK_RENDER_PASS_CONTENTS_INLINE) : (vk::VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS);
+
+	VK_CHECK(m_vki.beginCommandBuffer(*mainCmd, &mainCmdBufBeginInfo));
+	m_vki.cmdBeginRenderPass(*mainCmd, &renderPassBeginInfo, passContents);
+
+	if (m_isPrimaryCmdBuf)
+	{
+		m_vki.cmdBindPipeline(*mainCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+		writeDrawCmdBuffer(*mainCmd);
+	}
+	else
+	{
+		VK_CHECK(m_vki.beginCommandBuffer(*passCmd, &passCmdBufBeginInfo));
+		m_vki.cmdBindPipeline(*passCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+		writeDrawCmdBuffer(*passCmd);
+		VK_CHECK(m_vki.endCommandBuffer(*passCmd));
+
+		m_vki.cmdExecuteCommands(*mainCmd, 1, &passCmd.get());
+	}
+
+	m_vki.cmdEndRenderPass(*mainCmd);
+	VK_CHECK(m_vki.endCommandBuffer(*mainCmd));
+
+	// submit and wait for them to finish before exiting scope. (Killing in-flight objects is a no-no).
+	VK_CHECK(m_vki.queueSubmit(m_queue, 1, &mainCmd.get(), *fence));
+	VK_CHECK(m_vki.waitForFences(m_device, 1, &fence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
+}
+
+enum ShaderInputInterface
+{
+	SHADER_INPUT_SINGLE_DESCRIPTOR = 0,	//!< one descriptor
+	SHADER_INPUT_MULTIPLE_DESCRIPTORS,	//!< multiple descriptors
+	SHADER_INPUT_DESCRIPTOR_ARRAY,		//!< descriptor array
+
+	SHADER_INPUT_LAST
+};
+
+deUint32 getInterfaceNumResources (ShaderInputInterface shaderInterface)
+{
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:	return 1u;
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:	return 2u;
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:		return 2u;
+
+		default:
+			DE_FATAL("Impossible");
+			return 0u;
+	}
+}
+
+class BufferRenderInstance : public SingleCmdRenderInstance
+{
+public:
+													BufferRenderInstance		(Context&					context,
+																				 bool						isPrimaryCmdBuf,
+																				 vk::VkDescriptorType		descriptorType,
+																				 vk::VkShaderStageFlags		stageFlags,
+																				 ShaderInputInterface		shaderInterface,
+																				 bool						viewOffset,
+																				 bool						dynamicOffset,
+																				 bool						dynamicOffsetNonZero);
+
+	static vk::Move<vk::VkBuffer>					createSourceBuffer			(const vk::DeviceInterface&		vki,
+																				 vk::VkDevice					device,
+																				 vk::Allocator&					allocator,
+																				 vk::VkDescriptorType			descriptorType,
+																				 deUint32						offset,
+																				 deUint32						bufferSize,
+																				 de::MovePtr<vk::Allocation>*	outMemory);
+
+	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface);
+
+	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkShaderStageFlags		stageFlags);
+
+	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorSetLayout	descriptorSetLayout,
+																				 vk::VkDescriptorPool		descriptorPool,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkBuffer				sourceBufferA,
+																				 const deUint32				viewOffsetA,
+																				 vk::VkBuffer				sourceBufferB,
+																				 const deUint32				viewOffsetB);
+
+	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorSetLayout	descriptorSetLayout);
+
+	void											logTestPlan					(void) const;
+	vk::VkPipelineLayout							getPipelineLayout			(void) const;
+	void											writeDrawCmdBuffer			(vk::VkCmdBuffer cmd) const;
+	tcu::TestStatus									verifyResultImage			(const tcu::ConstPixelBufferAccess& result) const;
+
+	enum
+	{
+		RENDER_SIZE				= 128,
+		BUFFER_DATA_SIZE		= 8 * sizeof(float),
+		BUFFER_SIZE_A			= 2048, //!< a lot more than required
+		BUFFER_SIZE_B			= 2560, //!< a lot more than required
+
+		STATIC_OFFSET_VALUE_A	= 256,
+		DYNAMIC_OFFSET_VALUE_A	= 512,
+		STATIC_OFFSET_VALUE_B	= 1024,
+		DYNAMIC_OFFSET_VALUE_B	= 768,
+	};
+
+	const vk::VkDescriptorType						m_descriptorType;
+	const ShaderInputInterface						m_shaderInterface;
+	const bool										m_setViewOffset;
+	const bool										m_setDynamicOffset;
+	const bool										m_dynamicOffsetNonZero;
+	const vk::VkShaderStageFlags					m_stageFlags;
+
+	const deUint32									m_viewOffsetA;
+	const deUint32									m_viewOffsetB;
+	const deUint32									m_dynamicOffsetA;
+	const deUint32									m_dynamicOffsetB;
+	const deUint32									m_effectiveOffsetA;
+	const deUint32									m_effectiveOffsetB;
+	const deUint32									m_bufferSizeA;
+	const deUint32									m_bufferSizeB;
+
+	de::MovePtr<vk::Allocation>						m_bufferMemoryA;
+	de::MovePtr<vk::Allocation>						m_bufferMemoryB;
+	const vk::Unique<vk::VkBuffer>					m_sourceBufferA;
+	const vk::Unique<vk::VkBuffer>					m_sourceBufferB;
+	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
+	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
+	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
+	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
+};
+
+BufferRenderInstance::BufferRenderInstance	(Context&				context,
+											 bool					isPrimaryCmdBuf,
+											 vk::VkDescriptorType	descriptorType,
+											 vk::VkShaderStageFlags	stageFlags,
+											 ShaderInputInterface	shaderInterface,
+											 bool					viewOffset,
+											 bool					dynamicOffset,
+											 bool					dynamicOffsetNonZero)
+	: SingleCmdRenderInstance		(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
+	, m_descriptorType				(descriptorType)
+	, m_shaderInterface				(shaderInterface)
+	, m_setViewOffset				(viewOffset)
+	, m_setDynamicOffset			(dynamicOffset)
+	, m_dynamicOffsetNonZero		(dynamicOffsetNonZero)
+	, m_stageFlags					(stageFlags)
+	, m_viewOffsetA					((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u))
+	, m_viewOffsetB					((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u))
+	, m_dynamicOffsetA				((dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_A) : (0u))
+	, m_dynamicOffsetB				((dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_B) : (0u))
+	, m_effectiveOffsetA			((isDynamicDescriptorType(m_descriptorType)) ? (m_dynamicOffsetA) : (m_viewOffsetA))
+	, m_effectiveOffsetB			((isDynamicDescriptorType(m_descriptorType)) ? (m_dynamicOffsetB) : (m_viewOffsetB))
+	, m_bufferSizeA					(BUFFER_SIZE_A)
+	, m_bufferSizeB					(BUFFER_SIZE_B)
+	, m_bufferMemoryA				(DE_NULL)
+	, m_bufferMemoryB				(DE_NULL)
+	, m_sourceBufferA				(createSourceBuffer(m_vki, m_device, m_allocator, m_descriptorType, m_effectiveOffsetA, m_bufferSizeA, &m_bufferMemoryA))
+	, m_sourceBufferB				((getInterfaceNumResources(m_shaderInterface) == 1u)
+										? vk::Move<vk::VkBuffer>()
+										: createSourceBuffer(m_vki, m_device, m_allocator, m_descriptorType, m_effectiveOffsetB, m_bufferSizeB, &m_bufferMemoryB))
+	, m_descriptorPool				(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
+	, m_descriptorSetLayout			(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags))
+	, m_descriptorSet				(createDescriptorSet(m_vki, m_device, *m_descriptorSetLayout, *m_descriptorPool, m_descriptorType, m_shaderInterface, *m_sourceBufferA, m_viewOffsetA, *m_sourceBufferB, m_viewOffsetB))
+	, m_pipelineLayout				(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
+{
+	if (m_setDynamicOffset)
+		DE_ASSERT(isDynamicDescriptorType(m_descriptorType));
+	if (m_dynamicOffsetNonZero)
+		DE_ASSERT(m_setDynamicOffset);
+}
+
+vk::Move<vk::VkBuffer> BufferRenderInstance::createSourceBuffer (const vk::DeviceInterface&		vki,
+																 vk::VkDevice					device,
+																 vk::Allocator&					allocator,
+																 vk::VkDescriptorType			descriptorType,
+																 deUint32						offset,
+																 deUint32						bufferSize,
+																 de::MovePtr<vk::Allocation>*	outMemory)
+{
+	static const float				s_colors[]			=
+	{
+		0.0f, 1.0f, 0.0f, 1.0f,		// green
+		1.0f, 1.0f, 0.0f, 1.0f,		// yellow
+	};
+	DE_STATIC_ASSERT(sizeof(s_colors) == BUFFER_DATA_SIZE);
+	DE_ASSERT(offset + BUFFER_DATA_SIZE <= bufferSize);
+	DE_ASSERT(offset % sizeof(float) == 0);
+	DE_ASSERT(bufferSize % sizeof(float) == 0);
+
+	const bool						isUniformBuffer		= isUniformDescriptorType(descriptorType);
+	const vk::VkBufferUsageFlags	usageFlags			= (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+	const float						preGuardValue		= 0.5f;
+	const float						postGuardValue		= 0.75f;
+	const vk::VkBufferCreateInfo	bufferCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		bufferSize,						// size
+		usageFlags,						// usage
+		0u,								// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,	// sharingMode
+		0u,								// queueFamilyCount
+		DE_NULL,						// pQueueFamilyIndices
+	};
+	vk::Move<vk::VkBuffer>			buffer				(vk::createBuffer(vki, device, &bufferCreateInfo));
+	de::MovePtr<vk::Allocation>		bufferMemory		= allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible);
+	void* const						mapPtr				= bufferMemory->getHostPtr();
+
+	// guard with interesting values
+	for (size_t preGuardOffset = 0; preGuardOffset + sizeof(float) <= (size_t)offset; preGuardOffset += sizeof(float))
+		deMemcpy((deUint8*)mapPtr + preGuardOffset, &preGuardValue, sizeof(float));
+
+	deMemcpy((deUint8*)mapPtr + offset, s_colors, sizeof(s_colors));
+	for (size_t postGuardOffset = (size_t)offset + sizeof(s_colors); postGuardOffset + sizeof(float) <= (size_t)bufferSize; postGuardOffset += sizeof(float))
+		deMemcpy((deUint8*)mapPtr + postGuardOffset, &postGuardValue, sizeof(float));
+	deMemset((deUint8*)mapPtr + offset + sizeof(s_colors), 0x5A, (size_t)bufferSize - (size_t)offset - sizeof(s_colors)); // fill with interesting pattern that produces valid floats
+
+	flushMappedMemoryRange(vki, device, bufferMemory->getMemory(), bufferMemory->getOffset(), bufferSize);
+
+	*outMemory = bufferMemory;
+	return buffer;
+}
+
+vk::Move<vk::VkDescriptorPool> BufferRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
+																		   vk::VkDevice					device,
+																		   vk::VkDescriptorType			descriptorType,
+																		   ShaderInputInterface			shaderInterface)
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
+		.build(vki, device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSetLayout> BufferRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&	vki,
+																					 vk::VkDevice				device,
+																					 vk::VkDescriptorType		descriptorType,
+																					 ShaderInputInterface		shaderInterface,
+																					 vk::VkShaderStageFlags		stageFlags)
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(descriptorType, 2u, stageFlags);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return builder.build(vki, device);
+}
+
+vk::Move<vk::VkDescriptorSet> BufferRenderInstance::createDescriptorSet (const vk::DeviceInterface&	vki,
+																		 vk::VkDevice				device,
+																		 vk::VkDescriptorSetLayout	descriptorSetLayout,
+																		 vk::VkDescriptorPool		descriptorPool,
+																		 vk::VkDescriptorType		descriptorType,
+																		 ShaderInputInterface		shaderInterface,
+																		 vk::VkBuffer				bufferA,
+																		 deUint32					offsetA,
+																		 vk::VkBuffer				bufferB,
+																		 deUint32					offsetB)
+{
+	const vk::VkDescriptorInfo		bufferInfos[2]	=
+	{
+		createDescriptorInfo(bufferA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
+		createDescriptorInfo(bufferB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet	= allocDescriptorSet(vki, device, descriptorPool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, descriptorSetLayout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &bufferInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, bufferInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(vki, device);
+	return descriptorSet;
+}
+
+vk::Move<vk::VkPipelineLayout> BufferRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
+																		   vk::VkDevice					device,
+																		   vk::VkDescriptorSetLayout	descriptorSetLayout)
+{
+	const vk::VkPipelineLayoutCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		1,						// descriptorSetCount
+		&descriptorSetLayout,	// pSetLayouts
+		0u,						// pushConstantRangeCount
+		DE_NULL,				// pPushConstantRanges
+	};
+
+	return vk::createPipelineLayout(vki, device, &createInfo);
+}
+
+void BufferRenderInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Rendering 2x2 yellow-green grid.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
+		<< "Buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
+
+	if (isDynamicDescriptorType(m_descriptorType))
+	{
+		if (m_setDynamicOffset)
+		{
+			msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
+				<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
+		}
+		else
+		{
+			msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
+		}
+	}
+
+	if (m_stageFlags == 0u)
+	{
+		msg << "Descriptors are not accessed in any shader stage.\n";
+	}
+	else
+	{
+		msg << "Descriptors are accessed in {"
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)			? (" vertex")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)		? (" geometry")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)		? (" fragment")			: (""))
+			<< " } stages.\n";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+vk::VkPipelineLayout BufferRenderInstance::getPipelineLayout (void) const
+{
+	return *m_pipelineLayout;
+}
+
+void BufferRenderInstance::writeDrawCmdBuffer (vk::VkCmdBuffer cmd) const
+{
+	const bool							isUniformBuffer		= isUniformDescriptorType(m_descriptorType);
+
+	// \note dynamic offset replaces the view offset, i.e. it is not offset relative to the view offset
+	const deUint32						dynamicOffsets[]	=
+	{
+		m_dynamicOffsetA,
+		m_dynamicOffsetB,
+	};
+	const deUint32						numOffsets			= (!m_setDynamicOffset) ? (0u) : (getInterfaceNumResources(m_shaderInterface));
+	const deUint32* const				dynamicOffsetPtr	= (!m_setDynamicOffset) ? (DE_NULL) : (dynamicOffsets);
+
+	// make host writes device-visible
+	const vk::VkMemoryInputFlags		inputBit			= (isUniformBuffer) ? (vk::VK_MEMORY_INPUT_UNIFORM_READ_BIT) : (vk::VK_MEMORY_INPUT_SHADER_READ_BIT);
+	const vk::VkBufferMemoryBarrier		memoryBarrierA		=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,		// outputMask
+		inputBit,									// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
+		*m_sourceBufferA,							// buffer
+		0u,											// offset
+		(vk::VkDeviceSize)m_bufferSizeA,			// size
+	};
+	const vk::VkBufferMemoryBarrier		memoryBarrierB		=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,		// outputMask
+		inputBit,									// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
+		*m_sourceBufferB,							// buffer
+		0u,											// offset
+		(vk::VkDeviceSize)m_bufferSizeB,			// size
+	};
+	const void* const					memoryBarriers[2]	=
+	{
+		&memoryBarrierA,
+		&memoryBarrierB,
+	};
+	const deUint32						numMemoryBarriers	= getInterfaceNumResources(m_shaderInterface);
+
+	m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), numOffsets, dynamicOffsetPtr);
+	m_vki.cmdPipelineBarrier(cmd, 0u, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS, vk::VK_FALSE, numMemoryBarriers, memoryBarriers);
+	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
+}
+
+tcu::TestStatus BufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
+{
+	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
+	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
+
+	drawQuadrantReferenceResult(reference.getAccess(), yellow, green, green, yellow);
+
+	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
+		return tcu::TestStatus::fail("Image verification failed");
+	else
+		return tcu::TestStatus::pass("Pass");
+}
+
+class ComputeInstanceResultBuffer
+{
+public:
+	enum
+	{
+		DATA_SIZE = sizeof(tcu::Vec4[4])
+	};
+
+											ComputeInstanceResultBuffer	(const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 vk::Allocator&					allocator);
+
+	void									readResultContentsTo		(tcu::Vec4 (*results)[4]) const;
+
+	inline vk::VkBuffer						getBuffer					(void) const { return *m_buffer;			}
+	inline const void*						getResultReadBarrier		(void) const { return &m_bufferBarrier;		}
+
+private:
+	static vk::Move<vk::VkBuffer>			createResultBuffer			(const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 vk::Allocator&					allocator,
+																		 de::MovePtr<vk::Allocation>*	outAllocation);
+
+	static vk::VkBufferMemoryBarrier		createResultBufferBarrier	(vk::VkBuffer buffer);
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+
+	de::MovePtr<vk::Allocation>				m_bufferMem;
+	const vk::Unique<vk::VkBuffer>			m_buffer;
+	const vk::VkBufferMemoryBarrier			m_bufferBarrier;
+};
+
+ComputeInstanceResultBuffer::ComputeInstanceResultBuffer (const vk::DeviceInterface&	vki,
+														  vk::VkDevice					device,
+														  vk::Allocator&				allocator)
+	: m_vki				(vki)
+	, m_device			(device)
+	, m_bufferMem		(DE_NULL)
+	, m_buffer			(createResultBuffer(m_vki, m_device, allocator, &m_bufferMem))
+	, m_bufferBarrier	(createResultBufferBarrier(*m_buffer))
+{
+}
+
+void ComputeInstanceResultBuffer::readResultContentsTo (tcu::Vec4 (*results)[4]) const
+{
+	invalidateMappedMemoryRange(m_vki, m_device, m_bufferMem->getMemory(), m_bufferMem->getOffset(), sizeof(*results));
+	deMemcpy(*results, m_bufferMem->getHostPtr(), sizeof(*results));
+}
+
+vk::Move<vk::VkBuffer> ComputeInstanceResultBuffer::createResultBuffer (const vk::DeviceInterface&		vki,
+																		vk::VkDevice					device,
+																		vk::Allocator&					allocator,
+																		de::MovePtr<vk::Allocation>*	outAllocation)
+{
+	const vk::VkBufferCreateInfo	createInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		(vk::VkDeviceSize)DATA_SIZE,				// size
+		vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// usage
+		0u,											// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
+		0u,											// queueFamilyCount
+		DE_NULL,									// pQueueFamilyIndices
+	};
+	vk::Move<vk::VkBuffer>			buffer		(vk::createBuffer(vki, device, &createInfo));
+	de::MovePtr<vk::Allocation>		allocation	(allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
+	const float						clearValue	= -1.0f;
+	void*							mapPtr		= allocation->getHostPtr();
+
+	for (size_t offset = 0; offset < DATA_SIZE; offset += sizeof(float))
+		deMemcpy(((deUint8*)mapPtr) + offset, &clearValue, sizeof(float));
+
+	flushMappedMemoryRange(vki, device, allocation->getMemory(), allocation->getOffset(), (vk::VkDeviceSize)DATA_SIZE);
+
+	*outAllocation = allocation;
+	return buffer;
+}
+
+vk::VkBufferMemoryBarrier ComputeInstanceResultBuffer::createResultBufferBarrier (vk::VkBuffer buffer)
+{
+	const vk::VkBufferMemoryBarrier bufferBarrier =
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_SHADER_WRITE_BIT,		// outputMask
+		vk::VK_MEMORY_INPUT_HOST_READ_BIT,			// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
+		buffer,										// buffer
+		(vk::VkDeviceSize)0u,						// offset
+		DATA_SIZE,									// size
+	};
+	return bufferBarrier;
+}
+
+class ComputePipeline
+{
+public:
+											ComputePipeline			(const vk::DeviceInterface&			vki,
+																	 vk::VkDevice						device,
+																	 const vk::BinaryCollection&		programCollection,
+																	 deUint32							numDescriptorSets,
+																	 const vk::VkDescriptorSetLayout*	descriptorSetLayouts);
+
+	inline vk::VkPipeline					getPipeline				(void) const { return *m_pipeline;			};
+	inline vk::VkPipelineLayout				getPipelineLayout		(void) const { return *m_pipelineLayout;	};
+
+private:
+	static vk::Move<vk::VkPipelineLayout>	createPipelineLayout	(const vk::DeviceInterface&			vki,
+																	 vk::VkDevice						device,
+																	 deUint32							numDescriptorSets,
+																	 const vk::VkDescriptorSetLayout*	descriptorSetLayouts);
+
+	static vk::Move<vk::VkPipeline>			createPipeline			(const vk::DeviceInterface&			vki,
+																	 vk::VkDevice						device,
+																	 const vk::BinaryCollection&		programCollection,
+																	 vk::VkPipelineLayout				layout);
+
+	const vk::Unique<vk::VkPipelineLayout>	m_pipelineLayout;
+	const vk::Unique<vk::VkPipeline>		m_pipeline;
+};
+
+ComputePipeline::ComputePipeline (const vk::DeviceInterface&		vki,
+								  vk::VkDevice						device,
+								  const vk::BinaryCollection&		programCollection,
+								  deUint32							numDescriptorSets,
+								  const vk::VkDescriptorSetLayout*	descriptorSetLayouts)
+	: m_pipelineLayout	(createPipelineLayout(vki, device, numDescriptorSets, descriptorSetLayouts))
+	, m_pipeline		(createPipeline(vki, device, programCollection, *m_pipelineLayout))
+{
+}
+
+vk::Move<vk::VkPipelineLayout> ComputePipeline::createPipelineLayout (const vk::DeviceInterface&		vki,
+																	  vk::VkDevice						device,
+																	  deUint32							numDescriptorSets,
+																	  const vk::VkDescriptorSetLayout*	descriptorSetLayouts)
+{
+	const vk::VkPipelineLayoutCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		numDescriptorSets,		// descriptorSetCount
+		descriptorSetLayouts,	// pSetLayouts
+		0u,						// pushConstantRangeCount
+		DE_NULL,				// pPushConstantRanges
+	};
+	return vk::createPipelineLayout(vki, device, &createInfo);
+}
+
+vk::Move<vk::VkPipeline> ComputePipeline::createPipeline (const vk::DeviceInterface&	vki,
+														  vk::VkDevice					device,
+														  const vk::BinaryCollection&	programCollection,
+														  vk::VkPipelineLayout			layout)
+{
+	const vk::Unique<vk::VkShaderModule>		computeModule		(vk::createShaderModule(vki, device, programCollection.get("compute"), (vk::VkShaderModuleCreateFlags)0u));
+	const vk::VkShaderCreateInfo				shaderCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,
+		DE_NULL,
+		*computeModule,		// module
+		"main",				// pName
+		0u,					// flags
+		vk::VK_SHADER_STAGE_COMPUTE
+	};
+	const vk::Unique<vk::VkShader>				computeShader		(vk::createShader(vki, device, &shaderCreateInfo));
+	const vk::VkPipelineShaderStageCreateInfo	cs					=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+		DE_NULL,
+		vk::VK_SHADER_STAGE_COMPUTE,	// stage
+		*computeShader,					// shader
+		DE_NULL,						// pSpecializationInfo
+	};
+	const vk::VkComputePipelineCreateInfo		createInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+		DE_NULL,
+		cs,								// cs
+		0u,								// flags
+		layout,							// layout
+		(vk::VkPipeline)0,				// basePipelineHandle
+		0u,								// basePipelineIndex
+	};
+	return createComputePipeline(vki, device, (vk::VkPipelineCache)0u, &createInfo);
+}
+
+class ComputeCommand
+{
+public:
+										ComputeCommand	(const vk::DeviceInterface&	vki,
+														 vk::VkDevice				device,
+														 vk::VkPipeline				pipeline,
+														 vk::VkPipelineLayout		pipelineLayout,
+														 const tcu::UVec3&			numWorkGroups,
+														 int						numDescriptorSets,
+														 const vk::VkDescriptorSet*	descriptorSets,
+														 int						numDynamicOffsets,
+														 const deUint32*			dynamicOffsets,
+														 int						numPreBarriers,
+														 const void* const*			preBarriers,
+														 int						numPostBarriers,
+														 const void* const*			postBarriers);
+
+	void								submitAndWait	(deUint32 queueFamilyIndex, vk::VkQueue queue) const;
+
+private:
+	const vk::DeviceInterface&			m_vki;
+	const vk::VkDevice					m_device;
+	const vk::VkPipeline				m_pipeline;
+	const vk::VkPipelineLayout			m_pipelineLayout;
+	const tcu::UVec3&					m_numWorkGroups;
+	const int							m_numDescriptorSets;
+	const vk::VkDescriptorSet* const	m_descriptorSets;
+	const int							m_numDynamicOffsets;
+	const deUint32* const				m_dynamicOffsets;
+	const int							m_numPreBarriers;
+	const void* const* const			m_preBarriers;
+	const int							m_numPostBarriers;
+	const void* const* const			m_postBarriers;
+};
+
+ComputeCommand::ComputeCommand (const vk::DeviceInterface&	vki,
+								vk::VkDevice				device,
+								vk::VkPipeline				pipeline,
+								vk::VkPipelineLayout		pipelineLayout,
+								const tcu::UVec3&			numWorkGroups,
+								int							numDescriptorSets,
+								const vk::VkDescriptorSet*	descriptorSets,
+								int							numDynamicOffsets,
+								const deUint32*				dynamicOffsets,
+								int							numPreBarriers,
+								const void* const*			preBarriers,
+								int							numPostBarriers,
+								const void* const*			postBarriers)
+	: m_vki					(vki)
+	, m_device				(device)
+	, m_pipeline			(pipeline)
+	, m_pipelineLayout		(pipelineLayout)
+	, m_numWorkGroups		(numWorkGroups)
+	, m_numDescriptorSets	(numDescriptorSets)
+	, m_descriptorSets		(descriptorSets)
+	, m_numDynamicOffsets	(numDynamicOffsets)
+	, m_dynamicOffsets		(dynamicOffsets)
+	, m_numPreBarriers		(numPreBarriers)
+	, m_preBarriers			(preBarriers)
+	, m_numPostBarriers		(numPostBarriers)
+	, m_postBarriers		(postBarriers)
+{
+}
+
+void ComputeCommand::submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue) const
+{
+	const vk::VkCmdPoolCreateInfo					cmdPoolCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
+		DE_NULL,
+		queueFamilyIndex,						// queueFamilyIndex
+		vk::VK_CMD_POOL_CREATE_TRANSIENT_BIT,	// flags
+	};
+	const vk::Unique<vk::VkCmdPool>					cmdPool				(vk::createCommandPool(m_vki, m_device, &cmdPoolCreateInfo));
+
+	const vk::VkFenceCreateInfo						fenceCreateInfo		=
+	{
+		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+		DE_NULL,
+		0u,			// flags
+	};
+
+	const vk::VkCmdBufferCreateInfo					cmdBufCreateInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		*cmdPool,							// cmdPool
+		vk::VK_CMD_BUFFER_LEVEL_PRIMARY,	// level
+		0u,									// flags
+	};
+	const vk::VkCmdBufferBeginInfo					cmdBufBeginInfo		=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(vk::VkRenderPass)0u,																			// renderPass
+		0u,																								// subpass
+		(vk::VkFramebuffer)0u,																			// framebuffer
+	};
+
+	const vk::Unique<vk::VkFence>					cmdCompleteFence	(vk::createFence(m_vki, m_device, &fenceCreateInfo));
+	const vk::Unique<vk::VkCmdBuffer>				cmd					(vk::createCommandBuffer(m_vki, m_device, &cmdBufCreateInfo));
+	const deUint64									infiniteTimeout		= ~(deUint64)0u;
+
+	VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
+
+	m_vki.cmdBindPipeline(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline);
+	m_vki.cmdBindDescriptorSets(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, m_numDescriptorSets, m_descriptorSets, m_numDynamicOffsets, m_dynamicOffsets);
+
+	if (m_numPreBarriers)
+		m_vki.cmdPipelineBarrier(*cmd, 0u, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_FALSE, m_numPreBarriers, m_preBarriers);
+
+	m_vki.cmdDispatch(*cmd, m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
+	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_FALSE, m_numPostBarriers, m_postBarriers);
+	VK_CHECK(m_vki.endCommandBuffer(*cmd));
+
+	// run
+	VK_CHECK(m_vki.queueSubmit(queue, 1, &cmd.get(), *cmdCompleteFence));
+	VK_CHECK(m_vki.waitForFences(m_device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
+}
+
+class BufferComputeInstance : public vkt::TestInstance
+{
+public:
+											BufferComputeInstance		(Context&				context,
+																		 vk::VkDescriptorType	descriptorType,
+																		 ShaderInputInterface	shaderInterface,
+																		 bool					viewOffset,
+																		 bool					dynamicOffset,
+																		 bool					dynamicOffsetNonZero);
+
+private:
+	vk::Move<vk::VkBuffer>					createColorDataBuffer		(deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation);
+	vk::Move<vk::VkBufferView>				createBufferView			(vk::VkBuffer buffer, deUint32 offset) const;
+	vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(void) const;
+	vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(void) const;
+	vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf) const;
+
+	tcu::TestStatus							iterate						(void);
+	void									logTestPlan					(void) const;
+	tcu::TestStatus							testResourceAccess			(void);
+
+	enum
+	{
+		STATIC_OFFSET_VALUE_A	= 256,
+		DYNAMIC_OFFSET_VALUE_A	= 512,
+		STATIC_OFFSET_VALUE_B	= 1024,
+		DYNAMIC_OFFSET_VALUE_B	= 768,
+	};
+
+	const vk::VkDescriptorType				m_descriptorType;
+	const ShaderInputInterface				m_shaderInterface;
+	const bool								m_setViewOffset;
+	const bool								m_setDynamicOffset;
+	const bool								m_dynamicOffsetNonZero;
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+	const vk::VkQueue						m_queue;
+	const deUint32							m_queueFamilyIndex;
+	vk::Allocator&							m_allocator;
+
+	const ComputeInstanceResultBuffer		m_result;
+};
+
+BufferComputeInstance::BufferComputeInstance (Context&					context,
+											  vk::VkDescriptorType		descriptorType,
+											  ShaderInputInterface		shaderInterface,
+											  bool						viewOffset,
+											  bool						dynamicOffset,
+											  bool						dynamicOffsetNonZero)
+	: vkt::TestInstance			(context)
+	, m_descriptorType			(descriptorType)
+	, m_shaderInterface			(shaderInterface)
+	, m_setViewOffset			(viewOffset)
+	, m_setDynamicOffset		(dynamicOffset)
+	, m_dynamicOffsetNonZero	(dynamicOffsetNonZero)
+	, m_vki						(context.getDeviceInterface())
+	, m_device					(context.getDevice())
+	, m_queue					(context.getUniversalQueue())
+	, m_queueFamilyIndex		(context.getUniversalQueueFamilyIndex())
+	, m_allocator				(context.getDefaultAllocator())
+	, m_result					(m_vki, m_device, m_allocator)
+{
+	if (m_dynamicOffsetNonZero)
+		DE_ASSERT(m_setDynamicOffset);
+}
+
+vk::Move<vk::VkBuffer> BufferComputeInstance::createColorDataBuffer (deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation)
+{
+	DE_ASSERT(offset + sizeof(tcu::Vec4[2]) <= bufferSize);
+
+	const bool						isUniformBuffer		= isUniformDescriptorType(m_descriptorType);
+	const vk::VkBufferUsageFlags	usageFlags			= (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+	const vk::VkBufferCreateInfo	createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		(vk::VkDeviceSize)bufferSize,	// size
+		usageFlags,						// usage
+		0u,								// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,	// sharingMode
+		0u,								// queueFamilyCount
+		DE_NULL,						// pQueueFamilyIndices
+	};
+	vk::Move<vk::VkBuffer>			buffer				(vk::createBuffer(m_vki, m_device, &createInfo));
+	de::MovePtr<vk::Allocation>		allocation			(allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible));
+	void*							mapPtr				= allocation->getHostPtr();
+
+	if (offset)
+		deMemset(mapPtr, 0x5A, (size_t)offset);
+	deMemcpy((deUint8*)mapPtr + offset, value1.getPtr(), sizeof(tcu::Vec4));
+	deMemcpy((deUint8*)mapPtr + offset + sizeof(tcu::Vec4), value2.getPtr(), sizeof(tcu::Vec4));
+	deMemset((deUint8*)mapPtr + offset + 2 * sizeof(tcu::Vec4), 0x5A, (size_t)bufferSize - (size_t)offset - 2 * sizeof(tcu::Vec4));
+
+	flushMappedMemoryRange(m_vki, m_device, allocation->getMemory(), allocation->getOffset(), bufferSize);
+
+	*outAllocation = allocation;
+	return buffer;
+}
+
+vk::Move<vk::VkDescriptorSetLayout> BufferComputeInstance::createDescriptorSetLayout (void) const
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	};
+
+	return builder.build(m_vki, m_device);
+}
+
+vk::Move<vk::VkDescriptorPool> BufferComputeInstance::createDescriptorPool (void) const
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
+		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> BufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf) const
+{
+	const vk::VkDescriptorInfo		resultInfo		= createDescriptorInfo(resBuf, 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
+	const vk::VkDescriptorInfo		bufferInfos[2]	=
+	{
+		createDescriptorInfo(viewA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
+		createDescriptorInfo(viewB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet	= allocDescriptorSet(m_vki, m_device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// result
+	builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
+
+	// buffers
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &bufferInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &bufferInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &bufferInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, bufferInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(m_vki, m_device);
+	return descriptorSet;
+}
+
+tcu::TestStatus BufferComputeInstance::iterate (void)
+{
+	logTestPlan();
+	return testResourceAccess();
+}
+
+void BufferComputeInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Accessing resource in a compute program.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+				(m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+				(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+				(const char*)DE_NULL)
+		<< " source descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType)
+		<< " and one destination VK_DESCRIPTOR_TYPE_STORAGE_BUFFER to store results to.\n"
+		<< "Source descriptor buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
+
+	if (isDynamicDescriptorType(m_descriptorType))
+	{
+		if (m_setDynamicOffset)
+		{
+			msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
+				<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
+		}
+		else
+		{
+			msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
+		}
+	}
+
+	msg << "Destination buffer is pre-initialized to -1.\n";
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+tcu::TestStatus BufferComputeInstance::testResourceAccess (void)
+{
+	enum
+	{
+		ADDRESSABLE_SIZE = 256, // allocate a lot more than required
+	};
+
+	const bool										isDynamicCase		= isDynamicDescriptorType(m_descriptorType);
+	const bool										isUniformBuffer		= isUniformDescriptorType(m_descriptorType);
+	const deUint32									bindTimeOffsets[]	=
+	{
+		(m_dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_A) : (0u),
+		(m_dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_B) : (0u),
+	};
+
+	const tcu::Vec4									colorA1				= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4									colorA2				= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4									colorB1				= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
+	const tcu::Vec4									colorB2				= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
+
+	const deUint32									dataOffsetA			= (isDynamicCase) ? (bindTimeOffsets[0]) : (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u);
+	const deUint32									dataOffsetB			= (isDynamicCase) ? (bindTimeOffsets[1]) : (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u);
+	const deUint32									viewOffsetA			= (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u);
+	const deUint32									viewOffsetB			= (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u);
+	const deUint32									bufferSizeA			= dataOffsetA + ADDRESSABLE_SIZE;
+	const deUint32									bufferSizeB			= dataOffsetB + ADDRESSABLE_SIZE;
+
+	de::MovePtr<vk::Allocation>						bufferMemA;
+	const vk::Unique<vk::VkBuffer>					bufferA				(createColorDataBuffer(dataOffsetA, bufferSizeA, colorA1, colorA2, &bufferMemA));
+
+	de::MovePtr<vk::Allocation>						bufferMemB;
+	const vk::Unique<vk::VkBuffer>					bufferB				((getInterfaceNumResources(m_shaderInterface) == 1u)
+																			? (vk::Move<vk::VkBuffer>())
+																			: (createColorDataBuffer(dataOffsetB, bufferSizeB, colorB1, colorB2, &bufferMemB)));
+
+	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
+	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
+	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout, *bufferA, viewOffsetA, *bufferB, viewOffsetB, m_result.getBuffer()));
+	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
+
+	const vk::VkMemoryInputFlags					inputBit			= (isUniformBuffer) ? (vk::VK_MEMORY_INPUT_UNIFORM_READ_BIT) : (vk::VK_MEMORY_INPUT_SHADER_READ_BIT);
+	const vk::VkBufferMemoryBarrier					bufferBarrierA		=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,		// outputMask
+		inputBit,									// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
+		*bufferA,									// buffer
+		(vk::VkDeviceSize)0u,						// offset
+		(vk::VkDeviceSize)bufferSizeA,				// size
+	};
+	const vk::VkBufferMemoryBarrier					bufferBarrierB		=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,		// outputMask
+		inputBit,									// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
+		*bufferB,									// buffer
+		(vk::VkDeviceSize)0u,						// offset
+		(vk::VkDeviceSize)bufferSizeB,				// size
+	};
+
+	const deUint32									numSrcBuffers		= getInterfaceNumResources(m_shaderInterface);
+
+	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
+	const int										numDescriptorSets	= DE_LENGTH_OF_ARRAY(descriptorSets);
+	const deUint32* const							dynamicOffsets		= (m_setDynamicOffset) ? (bindTimeOffsets) : (DE_NULL);
+	const deUint32									numDynamicOffsets	= (m_setDynamicOffset) ? (numSrcBuffers) : (0);
+	const void* const								preBarriers[]		= { &bufferBarrierA, &bufferBarrierB };
+	const int										numPreBarriers		= numSrcBuffers;
+	const void* const								postBarriers[]		= { m_result.getResultReadBarrier() };
+	const int										numPostBarriers		= DE_LENGTH_OF_ARRAY(postBarriers);
+
+	const ComputeCommand							compute				(m_vki,
+																		 m_device,
+																		 pipeline.getPipeline(),
+																		 pipeline.getPipelineLayout(),
+																		 tcu::UVec3(4, 1, 1),
+																		 numDescriptorSets,	descriptorSets,
+																		 numDynamicOffsets,	dynamicOffsets,
+																		 numPreBarriers,	preBarriers,
+																		 numPostBarriers,	postBarriers);
+
+	const tcu::Vec4									refQuadrantValue14	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? (colorA2) :
+																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? (colorB2) :
+																		  (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? (colorB2) :
+																																	(tcu::Vec4(-2.0f));
+	const tcu::Vec4									refQuadrantValue23	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? (colorA1) :
+																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? (colorA1) :
+																		  (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? (colorA1) :
+																																	(tcu::Vec4(-2.0f));
+	const tcu::Vec4									references[4]		=
+	{
+		refQuadrantValue14,
+		refQuadrantValue23,
+		refQuadrantValue23,
+		refQuadrantValue14,
+	};
+	tcu::Vec4										results[4];
+
+	compute.submitAndWait(m_queueFamilyIndex, m_queue);
+	m_result.readResultContentsTo(&results);
+
+	// verify
+	if (results[0] == references[0] &&
+		results[1] == references[1] &&
+		results[2] == references[2] &&
+		results[3] == references[3])
+	{
+		return tcu::TestStatus::pass("Pass");
+	}
+	else if (results[0] == tcu::Vec4(-1.0f) &&
+			 results[1] == tcu::Vec4(-1.0f) &&
+			 results[2] == tcu::Vec4(-1.0f) &&
+			 results[3] == tcu::Vec4(-1.0f))
+	{
+		m_context.getTestContext().getLog()
+			<< tcu::TestLog::Message
+			<< "Result buffer was not written to."
+			<< tcu::TestLog::EndMessage;
+		return tcu::TestStatus::fail("Result buffer was not written to");
+	}
+	else
+	{
+		m_context.getTestContext().getLog()
+			<< tcu::TestLog::Message
+			<< "Error expected ["
+				<< references[0] << ", "
+				<< references[1] << ", "
+				<< references[2] << ", "
+				<< references[3] << "], got ["
+				<< results[0] << ", "
+				<< results[1] << ", "
+				<< results[2] << ", "
+				<< results[3] << "]"
+			<< tcu::TestLog::EndMessage;
+		return tcu::TestStatus::fail("Invalid result values");
+	}
+}
+
+class QuadrantRendederCase : public vkt::TestCase
+{
+public:
+									QuadrantRendederCase		(tcu::TestContext&		testCtx,
+																 const char*			name,
+																 const char*			description,
+																 glu::GLSLVersion		glslVersion,
+																 vk::VkShaderStageFlags	exitingStages,
+																 vk::VkShaderStageFlags	activeStages);
+private:
+	virtual std::string				genExtensionDeclarations	(vk::VkShaderStage stage) const = 0;
+	virtual std::string				genResourceDeclarations		(vk::VkShaderStage stage, int numUsedBindings) const = 0;
+	virtual std::string				genResourceAccessSource		(vk::VkShaderStage stage) const = 0;
+	virtual std::string				genNoAccessSource			(void) const = 0;
+
+	std::string						genVertexSource				(void) const;
+	std::string						genTessCtrlSource			(void) const;
+	std::string						genTessEvalSource			(void) const;
+	std::string						genGeometrySource			(void) const;
+	std::string						genFragmentSource			(void) const;
+	std::string						genComputeSource			(void) const;
+
+	void							initPrograms				(vk::SourceCollections& programCollection) const;
+
+protected:
+	const glu::GLSLVersion			m_glslVersion;
+	const vk::VkShaderStageFlags	m_exitingStages;
+	const vk::VkShaderStageFlags	m_activeStages;
+};
+
+QuadrantRendederCase::QuadrantRendederCase (tcu::TestContext&		testCtx,
+											const char*				name,
+											const char*				description,
+											glu::GLSLVersion		glslVersion,
+											vk::VkShaderStageFlags	exitingStages,
+											vk::VkShaderStageFlags	activeStages)
+	: vkt::TestCase		(testCtx, name, description)
+	, m_glslVersion		(glslVersion)
+	, m_exitingStages	(exitingStages)
+	, m_activeStages	(activeStages)
+{
+	DE_ASSERT((m_exitingStages & m_activeStages) == m_activeStages);
+}
+
+std::string QuadrantRendederCase::genVertexSource (void) const
+{
+	const char* const	nextStageName	= ((m_exitingStages & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0u)	? ("tsc")
+										: ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)		? ("geo")
+										: ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)		? ("frag")
+										: (DE_NULL);
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	std::ostringstream	buf;
+
+	if ((m_activeStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
+	{
+		// active vertex shader
+		buf << versionDecl << "\n"
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX)
+			<< genResourceDeclarations(vk::VK_SHADER_STAGE_VERTEX, 0)
+			<< "layout(location = 0) out highp vec4 " << nextStageName << "_color;\n"
+			<< "layout(location = 1) flat out highp int " << nextStageName << "_quadrant_id;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp vec4 result_position;\n"
+			<< "	highp int quadrant_id;\n"
+			<< s_quadrantGenVertexPosSource
+			<< "	gl_Position = result_position;\n"
+			<< "	" << nextStageName << "_quadrant_id = quadrant_id;\n"
+			<< "\n"
+			<< "	highp vec4 result_color;\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_VERTEX)
+			<< "	" << nextStageName << "_color = result_color;\n"
+			<< "}\n";
+	}
+	else
+	{
+		// do nothing
+		buf << versionDecl << "\n"
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX)
+			<< "layout(location = 1) flat out highp int " << nextStageName << "_quadrant_id;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp vec4 result_position;\n"
+			<< "	highp int quadrant_id;\n"
+			<< s_quadrantGenVertexPosSource
+			<< "	gl_Position = result_position;\n"
+			<< "	" << nextStageName << "_quadrant_id = quadrant_id;\n"
+			<< "}\n";
+	}
+
+	return buf.str();
+}
+
+std::string QuadrantRendederCase::genTessCtrlSource (void) const
+{
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
+	const char* const	tessExtDecl		= extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
+	std::ostringstream	buf;
+
+	if ((m_activeStages & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0u)
+	{
+		// contributing not implemented
+		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESS_CONTROL_BIT);
+
+		// active tc shader
+		buf << versionDecl << "\n"
+			<< tessExtDecl
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESS_CONTROL)
+			<< "layout(vertices=3) out;\n"
+			<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESS_CONTROL, 0)
+			<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
+			<< "layout(location = 0) out highp vec4 tes_color[];\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp vec4 result_color;\n"
+			<< "	highp int quadrant_id = tsc_quadrant_id[gl_InvocationID];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESS_CONTROL)
+			<< "\n"
+			<< "	tes_color[gl_InvocationID] = result_color;\n"
+			<< "\n"
+			<< "	// no dynamic input block indexing\n"
+			<< "	highp vec4 position;\n"
+			<< "	if (gl_InvocationID == 0)\n"
+			<< "		position = gl_in[0].gl_Position;\n"
+			<< "	else if (gl_InvocationID == 1)\n"
+			<< "		position = gl_in[1].gl_Position;\n"
+			<< "	else\n"
+			<< "		position = gl_in[2].gl_Position;\n"
+			<< "	gl_out[gl_InvocationID].gl_Position = position;\n"
+			<< "	gl_TessLevelInner[0] = 2.8;\n"
+			<< "	gl_TessLevelInner[1] = 2.8;\n"
+			<< "	gl_TessLevelOuter[0] = 2.8;\n"
+			<< "	gl_TessLevelOuter[1] = 2.8;\n"
+			<< "	gl_TessLevelOuter[2] = 2.8;\n"
+			<< "	gl_TessLevelOuter[3] = 2.8;\n"
+			<< "}\n";
+	}
+	else if ((m_activeStages & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0u)
+	{
+		// active te shader, tc passthru
+		buf << versionDecl << "\n"
+			<< tessExtDecl
+			<< "layout(vertices=3) out;\n"
+			<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
+			<< "layout(location = 1) flat out highp int tes_quadrant_id[];\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	tes_quadrant_id[gl_InvocationID] = tsc_quadrant_id[0];\n"
+			<< "\n"
+			<< "	// no dynamic input block indexing\n"
+			<< "	highp vec4 position;\n"
+			<< "	if (gl_InvocationID == 0)\n"
+			<< "		position = gl_in[0].gl_Position;\n"
+			<< "	else if (gl_InvocationID == 1)\n"
+			<< "		position = gl_in[1].gl_Position;\n"
+			<< "	else\n"
+			<< "		position = gl_in[2].gl_Position;\n"
+			<< "	gl_out[gl_InvocationID].gl_Position = position;\n"
+			<< "	gl_TessLevelInner[0] = 2.8;\n"
+			<< "	gl_TessLevelInner[1] = 2.8;\n"
+			<< "	gl_TessLevelOuter[0] = 2.8;\n"
+			<< "	gl_TessLevelOuter[1] = 2.8;\n"
+			<< "	gl_TessLevelOuter[2] = 2.8;\n"
+			<< "	gl_TessLevelOuter[3] = 2.8;\n"
+			<< "}\n";
+	}
+	else
+	{
+		// passthrough not implemented
+		DE_FATAL("not implemented");
+	}
+
+	return buf.str();
+}
+
+std::string QuadrantRendederCase::genTessEvalSource (void) const
+{
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
+	const char* const	tessExtDecl		= extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
+	std::ostringstream	buf;
+
+	if ((m_activeStages & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0u)
+	{
+		// contributing not implemented
+		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT);
+
+		// active te shader
+		buf << versionDecl << "\n"
+			<< tessExtDecl
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESS_EVALUATION)
+			<< "layout(triangles) in;\n"
+			<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESS_EVALUATION, 0)
+			<< "layout(location = 1) flat in highp int tes_quadrant_id[];\n"
+			<< "layout(location = 0) out highp vec4 frag_color;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp vec4 result_color;\n"
+			<< "	highp int quadrant_id = tes_quadrant_id[0];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESS_EVALUATION)
+			<< "\n"
+			<< "	frag_color = result_color;\n"
+			<< "	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
+			<< "}\n";
+	}
+	else if ((m_activeStages & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0u)
+	{
+		// contributing not implemented
+		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESS_CONTROL_BIT);
+
+		// active tc shader, te is passthru
+		buf << versionDecl << "\n"
+			<< tessExtDecl
+			<< "layout(triangles) in;\n"
+			<< "layout(location = 0) in highp vec4 tes_color[];\n"
+			<< "layout(location = 0) out highp vec4 frag_color;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	frag_color = tes_color[0];\n"
+			<< "	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
+			<< "}\n";
+	}
+	else
+	{
+		// passthrough not implemented
+		DE_FATAL("not implemented");
+	}
+
+	return buf.str();
+}
+
+std::string QuadrantRendederCase::genGeometrySource (void) const
+{
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
+	const char* const	geomExtDecl		= extRequired ? "#extension GL_EXT_geometry_shader : require\n" : "";
+	std::ostringstream	buf;
+
+	if ((m_activeStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
+	{
+		// contributing not implemented
+		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_GEOMETRY_BIT);
+
+		// active geometry shader
+		buf << versionDecl << "\n"
+			<< geomExtDecl
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< "layout(triangles) in;\n"
+			<< "layout(triangle_strip, max_vertices=4) out;\n"
+			<< genResourceDeclarations(vk::VK_SHADER_STAGE_GEOMETRY, 0)
+			<< "layout(location = 1) flat in highp int geo_quadrant_id[];\n"
+			<< "layout(location = 0) out highp vec4 frag_color;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp int quadrant_id;\n"
+			<< "	highp vec4 result_color;\n"
+			<< "\n"
+			<< "	quadrant_id = geo_quadrant_id[0];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< "	frag_color = result_color;\n"
+			<< "	gl_Position = gl_in[0].gl_Position;\n"
+			<< "	EmitVertex();\n"
+			<< "\n"
+			<< "	quadrant_id = geo_quadrant_id[1];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< "	frag_color = result_color;\n"
+			<< "	gl_Position = gl_in[1].gl_Position;\n"
+			<< "	EmitVertex();\n"
+			<< "\n"
+			<< "	quadrant_id = geo_quadrant_id[2];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< "	frag_color = result_color;\n"
+			<< "	gl_Position = gl_in[0].gl_Position * 0.5 + gl_in[2].gl_Position * 0.5;\n"
+			<< "	EmitVertex();\n"
+			<< "\n"
+			<< "	quadrant_id = geo_quadrant_id[0];\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< "	frag_color = result_color;\n"
+			<< "	gl_Position = gl_in[2].gl_Position;\n"
+			<< "	EmitVertex();\n"
+			<< "}\n";
+	}
+	else
+	{
+		// passthrough not implemented
+		DE_FATAL("not implemented");
+	}
+
+	return buf.str();
+}
+
+std::string QuadrantRendederCase::genFragmentSource (void) const
+{
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	std::ostringstream	buf;
+
+	if ((m_activeStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
+	{
+		buf << versionDecl << "\n"
+			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY)
+			<< genResourceDeclarations(vk::VK_SHADER_STAGE_FRAGMENT, 0);
+
+		if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
+		{
+			// there are other stages, this is just a contributor
+			buf << "layout(location = 0) in mediump vec4 frag_color;\n";
+		}
+
+		buf << "layout(location = 1) flat in highp int frag_quadrant_id;\n"
+			<< "layout(location = 0) out mediump vec4 o_color;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp int quadrant_id = frag_quadrant_id;\n"
+			<< "	highp vec4 result_color;\n"
+			<< genResourceAccessSource(vk::VK_SHADER_STAGE_FRAGMENT);
+
+		if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
+		{
+			// just contributor
+			buf	<< "	if (frag_quadrant_id < 2)\n"
+				<< "		o_color = result_color;\n"
+				<< "	else\n"
+				<< "		o_color = frag_color;\n";
+		}
+		else
+			buf << "	o_color = result_color;\n";
+
+		buf << "}\n";
+	}
+	else if (m_activeStages == 0u)
+	{
+		// special case, no active stages
+		buf << versionDecl << "\n"
+			<< "layout(location = 1) flat in highp int frag_quadrant_id;\n"
+			<< "layout(location = 0) out mediump vec4 o_color;\n"
+			<< "void main (void)\n"
+			<< "{\n"
+			<< "	highp int quadrant_id = frag_quadrant_id;\n"
+			<< "	highp vec4 result_color;\n"
+			<< genNoAccessSource()
+			<< "	o_color = result_color;\n"
+			<< "}\n";
+	}
+	else
+	{
+		// passthrough
+		buf <<	versionDecl << "\n"
+			<<	"layout(location = 0) in mediump vec4 frag_color;\n"
+				"layout(location = 0) out mediump vec4 o_color;\n"
+				"void main (void)\n"
+				"{\n"
+				"	o_color = frag_color;\n"
+				"}\n";
+	}
+
+	return buf.str();
+}
+
+std::string QuadrantRendederCase::genComputeSource (void) const
+{
+	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
+	std::ostringstream	buf;
+
+	buf	<< versionDecl << "\n"
+		<< genExtensionDeclarations(vk::VK_SHADER_STAGE_COMPUTE)
+		<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
+		<< genResourceDeclarations(vk::VK_SHADER_STAGE_COMPUTE, 1)
+		<< "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
+		<< "{\n"
+		<< "	highp vec4 read_colors[4];\n"
+		<< "} b_out;\n"
+		<< "void main(void)\n"
+		<< "{\n"
+		<< "	highp int quadrant_id = int(gl_WorkGroupID.x);\n"
+		<< "	highp vec4 result_color;\n"
+		<< genResourceAccessSource(vk::VK_SHADER_STAGE_COMPUTE)
+		<< "	b_out.read_colors[gl_WorkGroupID.x] = result_color;\n"
+		<< "}\n";
+
+	return buf.str();
+}
+
+void QuadrantRendederCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
+		programCollection.glslSources.add("vertex") << glu::VertexSource(genVertexSource());
+
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0u)
+		programCollection.glslSources.add("tess_ctrl") << glu::TessellationControlSource(genTessCtrlSource());
+
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0u)
+		programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(genTessEvalSource());
+
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
+		programCollection.glslSources.add("geometry") << glu::GeometrySource(genGeometrySource());
+
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
+		programCollection.glslSources.add("fragment") << glu::FragmentSource(genFragmentSource());
+
+	if ((m_exitingStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) != 0u)
+		programCollection.glslSources.add("compute") << glu::ComputeSource(genComputeSource());
+}
+
+class BufferDescriptorCase : public QuadrantRendederCase
+{
+public:
+	enum
+	{
+		FLAG_VIEW_OFFSET			= (1u << 1u),
+		FLAG_DYNAMIC_OFFSET_ZERO	= (1u << 2u),
+		FLAG_DYNAMIC_OFFSET_NONZERO	= (1u << 3u),
+	};
+	// enum continues where resource flags ends
+	DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
+
+									BufferDescriptorCase		(tcu::TestContext&		testCtx,
+																 const char*			name,
+																 const char*			description,
+																 bool					isPrimaryCmdBuf,
+																 vk::VkDescriptorType	descriptorType,
+																 vk::VkShaderStageFlags	exitingStages,
+																 vk::VkShaderStageFlags	activeStages,
+																 ShaderInputInterface	shaderInterface,
+																 deUint32				flags);
+
+private:
+	std::string						genExtensionDeclarations	(vk::VkShaderStage stage) const;
+	std::string						genResourceDeclarations		(vk::VkShaderStage stage, int numUsedBindings) const;
+	std::string						genResourceAccessSource		(vk::VkShaderStage stage) const;
+	std::string						genNoAccessSource			(void) const;
+
+	vkt::TestInstance*				createInstance				(vkt::Context& context) const;
+
+	const bool						m_viewOffset;
+	const bool						m_dynamicOffsetSet;
+	const bool						m_dynamicOffsetNonZero;
+	const bool						m_isPrimaryCmdBuf;
+	const vk::VkDescriptorType		m_descriptorType;
+	const ShaderInputInterface		m_shaderInterface;
+};
+
+BufferDescriptorCase::BufferDescriptorCase (tcu::TestContext&		testCtx,
+											const char*				name,
+											const char*				description,
+											bool					isPrimaryCmdBuf,
+											vk::VkDescriptorType	descriptorType,
+											vk::VkShaderStageFlags	exitingStages,
+											vk::VkShaderStageFlags	activeStages,
+											ShaderInputInterface	shaderInterface,
+											deUint32				flags)
+	: QuadrantRendederCase		(testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages)
+	, m_viewOffset				((flags & FLAG_VIEW_OFFSET) != 0u)
+	, m_dynamicOffsetSet		((flags & (FLAG_DYNAMIC_OFFSET_ZERO | FLAG_DYNAMIC_OFFSET_NONZERO)) != 0u)
+	, m_dynamicOffsetNonZero	((flags & FLAG_DYNAMIC_OFFSET_NONZERO) != 0u)
+	, m_isPrimaryCmdBuf			(isPrimaryCmdBuf)
+	, m_descriptorType			(descriptorType)
+	, m_shaderInterface			(shaderInterface)
+{
+}
+
+std::string BufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+	return "";
+}
+
+std::string BufferDescriptorCase::genResourceDeclarations (vk::VkShaderStage stage, int numUsedBindings) const
+{
+	DE_UNREF(stage);
+
+	const bool			isUniform		= isUniformDescriptorType(m_descriptorType);
+	const char* const	storageType		= (isUniform) ? ("uniform") : ("buffer");
+	std::ostringstream	buf;
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferName\n"
+				<< "{\n"
+				<< "	highp vec4 colorA;\n"
+				<< "	highp vec4 colorB;\n"
+				<< "} b_instance;\n";
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferNameA\n"
+				<< "{\n"
+				<< "	highp vec4 colorA;\n"
+				<< "	highp vec4 colorB;\n"
+				<< "} b_instanceA;\n"
+				<< "layout(set = 0, binding = " << (numUsedBindings+1) << ", std140) " << storageType << " BufferNameB\n"
+				<< "{\n"
+				<< "	highp vec4 colorA;\n"
+				<< "	highp vec4 colorB;\n"
+				<< "} b_instanceB;\n";
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferName\n"
+				<< "{\n"
+				<< "	highp vec4 colorA;\n"
+				<< "	highp vec4 colorB;\n"
+				<< "} b_instances[2];\n";
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return buf.str();
+}
+
+std::string BufferDescriptorCase::genResourceAccessSource (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+
+	std::ostringstream buf;
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+				<< "		result_color = b_instance.colorA;\n"
+				<< "	else\n"
+				<< "		result_color = b_instance.colorB;\n";
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+				<< "		result_color = b_instanceA.colorA;\n"
+				<< "	else\n"
+				<< "		result_color = b_instanceB.colorB;\n";
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+				<< "		result_color = b_instances[0].colorA;\n"
+				<< "	else\n"
+				<< "		result_color = b_instances[1].colorB;\n";
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return buf.str();
+}
+
+std::string BufferDescriptorCase::genNoAccessSource (void) const
+{
+	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+		   "		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+		   "	else\n"
+		   "		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
+}
+
+vkt::TestInstance* BufferDescriptorCase::createInstance (vkt::Context& context) const
+{
+	if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
+	{
+		DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
+		return new BufferComputeInstance(context, m_descriptorType, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
+	}
+	else
+		return new BufferRenderInstance(context, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
+}
+
+class ImageInstanceImages
+{
+public:
+										ImageInstanceImages		(const vk::DeviceInterface&		vki,
+																 vk::VkDevice					device,
+																 deUint32						queueFamilyIndex,
+																 vk::VkQueue					queue,
+																 vk::Allocator&					allocator,
+																 vk::VkDescriptorType			descriptorType,
+																 vk::VkImageViewType			viewType,
+																 int							numImages,
+																 deUint32						baseMipLevel,
+																 deUint32						baseArraySlice);
+
+private:
+	static vk::Move<vk::VkImage>		createImage				(const vk::DeviceInterface&			vki,
+																 vk::VkDevice						device,
+																 vk::Allocator&						allocator,
+																 vk::VkDescriptorType				descriptorType,
+																 vk::VkImageViewType				viewType,
+																 const tcu::TextureLevelPyramid&	sourceImage,
+																 de::MovePtr<vk::Allocation>*		outAllocation);
+
+	static vk::Move<vk::VkImageView>	createImageView			(const vk::DeviceInterface&			vki,
+																 vk::VkDevice						device,
+																 vk::VkImageViewType				viewType,
+																 const tcu::TextureLevelPyramid&	sourceImage,
+																 vk::VkImage						image,
+																 deUint32							baseMipLevel,
+																 deUint32							baseArraySlice);
+
+	void								populateSourceImage		(tcu::TextureLevelPyramid*			dst,
+																 bool								isFirst) const;
+
+	void								uploadImage				(const vk::DeviceInterface&			vki,
+																 vk::VkDevice						device,
+																 deUint32							queueFamilyIndex,
+																 vk::VkQueue						queue,
+																 vk::Allocator&						allocator,
+																 vk::VkImage						image,
+																 const tcu::TextureLevelPyramid&	data);
+
+protected:
+	enum
+	{
+		IMAGE_SIZE		= 64,
+		NUM_MIP_LEVELS	= 2,
+		ARRAY_SIZE		= 2,
+	};
+
+	const vk::VkImageViewType			m_viewType;
+	const deUint32						m_baseMipLevel;
+	const deUint32						m_baseArraySlice;
+
+	const tcu::TextureFormat			m_imageFormat;
+	tcu::TextureLevelPyramid			m_sourceImageA;
+	tcu::TextureLevelPyramid			m_sourceImageB;
+
+	de::MovePtr<vk::Allocation>			m_imageMemoryA;
+	de::MovePtr<vk::Allocation>			m_imageMemoryB;
+	vk::Move<vk::VkImage>				m_imageA;
+	vk::Move<vk::VkImage>				m_imageB;
+	vk::Move<vk::VkImageView>			m_imageViewA;
+	vk::Move<vk::VkImageView>			m_imageViewB;
+};
+
+ImageInstanceImages::ImageInstanceImages (const vk::DeviceInterface&	vki,
+										  vk::VkDevice					device,
+										  deUint32						queueFamilyIndex,
+										  vk::VkQueue					queue,
+										  vk::Allocator&				allocator,
+										  vk::VkDescriptorType			descriptorType,
+										  vk::VkImageViewType			viewType,
+										  int							numImages,
+										  deUint32						baseMipLevel,
+										  deUint32						baseArraySlice)
+	: m_viewType		(viewType)
+	, m_baseMipLevel	(baseMipLevel)
+	, m_baseArraySlice	(baseArraySlice)
+	, m_imageFormat		(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
+	, m_sourceImageA	(m_imageFormat, NUM_MIP_LEVELS)
+	, m_sourceImageB	(m_imageFormat, NUM_MIP_LEVELS)
+	, m_imageMemoryA	(DE_NULL)
+	, m_imageMemoryB	(DE_NULL)
+	, m_imageA			(vk::Move<vk::VkImage>())
+	, m_imageB			(vk::Move<vk::VkImage>())
+	, m_imageViewA		(vk::Move<vk::VkImageView>())
+	, m_imageViewB		(vk::Move<vk::VkImageView>())
+{
+	DE_ASSERT(numImages == 1 || numImages == 2);
+
+	populateSourceImage(&m_sourceImageA, true);
+	m_imageA = createImage(vki, device, allocator, descriptorType, viewType, m_sourceImageA, &m_imageMemoryA);
+	m_imageViewA = createImageView(vki, device, viewType, m_sourceImageA, *m_imageA, m_baseMipLevel, m_baseArraySlice);
+	uploadImage(vki, device, queueFamilyIndex, queue, allocator, *m_imageA, m_sourceImageA);
+
+	if (numImages == 2)
+	{
+		populateSourceImage(&m_sourceImageB, false);
+		m_imageB = createImage(vki, device, allocator, descriptorType, viewType, m_sourceImageB, &m_imageMemoryB);
+		m_imageViewB = createImageView(vki, device, viewType, m_sourceImageB, *m_imageB, m_baseMipLevel, m_baseArraySlice);
+		uploadImage(vki, device, queueFamilyIndex, queue, allocator, *m_imageB, m_sourceImageB);
+	}
+}
+
+vk::Move<vk::VkImage> ImageInstanceImages::createImage (const vk::DeviceInterface&			vki,
+														vk::VkDevice						device,
+														vk::Allocator&						allocator,
+														vk::VkDescriptorType				descriptorType,
+														vk::VkImageViewType					viewType,
+														const tcu::TextureLevelPyramid&		sourceImage,
+														de::MovePtr<vk::Allocation>*		outAllocation)
+{
+	const tcu::ConstPixelBufferAccess	baseLevel	= sourceImage.getLevel(0);
+	const bool							isCube		= (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
+	const bool							isStorage	= (descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
+	const deUint32						readUsage	= (isStorage) ? (vk::VK_IMAGE_USAGE_STORAGE_BIT) : (vk::VK_IMAGE_USAGE_SAMPLED_BIT);
+	const deUint32						arraySize	= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (baseLevel.getHeight())
+													: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (baseLevel.getDepth())
+													: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)														? (1)
+													: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (baseLevel.getDepth()) // cube: numFaces * numLayers
+																																					: (0);
+	const vk::VkExtent3D				extent		=
+	{
+		// x
+		(deInt32)baseLevel.getWidth(),
+
+		// y
+		(viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1) : (deInt32)baseLevel.getHeight(),
+
+		// z
+		(viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ((deInt32)baseLevel.getDepth()) : (1),
+	};
+	const vk::VkImageCreateInfo			createInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+		DE_NULL,
+		viewTypeToImageType(viewType),											// imageType
+		mapToVkTextureFormat(baseLevel.getFormat()),							// format
+		extent,																	// extent
+		(deUint32)sourceImage.getNumLevels(),									// mipLevels
+		arraySize,																// arraySize
+		1,																		// samples
+		vk::VK_IMAGE_TILING_OPTIMAL,											// tiling
+		readUsage | vk::VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT,				// usage
+		isCube ? ((deUint32)vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) : (0u),	// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,											// sharingMode
+		0u,																		// queueFamilyCount
+		DE_NULL,																// pQueueFamilyIndices
+		vk::VK_IMAGE_LAYOUT_UNDEFINED,											// initialLayout
+	};
+	vk::Move<vk::VkImage>				image		(vk::createImage(vki, device, &createInfo));
+
+	*outAllocation = allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any);
+	return image;
+}
+
+vk::Move<vk::VkImageView> ImageInstanceImages::createImageView (const vk::DeviceInterface&			vki,
+																vk::VkDevice						device,
+																vk::VkImageViewType					viewType,
+																const tcu::TextureLevelPyramid&		sourceImage,
+																vk::VkImage							image,
+																deUint32							baseMipLevel,
+																deUint32							baseArraySlice)
+{
+	const tcu::ConstPixelBufferAccess	baseLevel			= sourceImage.getLevel(0);
+	const deUint32						viewTypeBaseSlice	= (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * baseArraySlice) : (baseArraySlice);
+	const deUint32						viewArraySize		= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D)			? (1)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (baseLevel.getHeight() - viewTypeBaseSlice)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D)			? (1)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (baseLevel.getDepth() - viewTypeBaseSlice)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)			? (1)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE)			? (6)
+															: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (baseLevel.getDepth() - viewTypeBaseSlice) // cube: numFaces * numLayers
+																												: (0);
+
+	DE_ASSERT(viewArraySize > 0);
+
+	const vk::VkImageSubresourceRange	resourceRange	=
+	{
+		vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
+		baseMipLevel,									// baseMipLevel
+		sourceImage.getNumLevels() - baseMipLevel,		// mipLevels
+		viewTypeBaseSlice,								// baseArraySlice
+		viewArraySize,									// arraySize
+	};
+	const vk::VkImageViewCreateInfo		createInfo		=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+		DE_NULL,
+		image,											// image
+		viewType,										// viewType
+		mapToVkTextureFormat(baseLevel.getFormat()),	// format
+		{
+			vk::VK_CHANNEL_SWIZZLE_R,
+			vk::VK_CHANNEL_SWIZZLE_G,
+			vk::VK_CHANNEL_SWIZZLE_B,
+			vk::VK_CHANNEL_SWIZZLE_A
+		},												// channels
+		resourceRange,									// subresourceRange
+		0u,												// flags
+	};
+	return vk::createImageView(vki, device, &createInfo);
+}
+
+void ImageInstanceImages::populateSourceImage (tcu::TextureLevelPyramid* dst, bool isFirst) const
+{
+	const int numLevels = dst->getNumLevels();
+
+	for (int level = 0; level < numLevels; ++level)
+	{
+		const int	width	= IMAGE_SIZE >> level;
+		const int	height	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (ARRAY_SIZE)
+																																: (IMAGE_SIZE >> level);
+		const int	depth	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (1)
+							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (ARRAY_SIZE)
+							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (6 * ARRAY_SIZE)
+							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? (IMAGE_SIZE >> level)
+																																: (1);
+
+		dst->allocLevel(level, width, height, depth);
+
+		{
+			const tcu::PixelBufferAccess levelAccess = dst->getLevel(level);
+
+			for (int z = 0; z < depth; ++z)
+			for (int y = 0; y < height; ++y)
+			for (int x = 0; x < width; ++x)
+			{
+				const int			gradPos	= x + y + z;
+				const int			gradMax	= width + height + depth - 3;
+
+				const int			red		= 255 * gradPos / gradMax;													//!< gradient from 0 -> max (detects large offset errors)
+				const int			green	= ((gradPos % 2 == 0) ? (127) : (0)) + ((gradPos % 4 < 3) ? (128) : (0));	//!< 3-level M pattern (detects small offset errors)
+				const int			blue	= (128 * level / numLevels) + (isFirst ? 127 : 0);							//!< level and image index (detects incorrect lod / image)
+
+				DE_ASSERT(de::inRange(red, 0, 255));
+				DE_ASSERT(de::inRange(green, 0, 255));
+				DE_ASSERT(de::inRange(blue, 0, 255));
+
+				levelAccess.setPixel(tcu::IVec4(red, green, blue, 255), x, y, z);
+			}
+		}
+	}
+}
+
+void ImageInstanceImages::uploadImage (const vk::DeviceInterface&		vki,
+									   vk::VkDevice						device,
+									   deUint32							queueFamilyIndex,
+									   vk::VkQueue						queue,
+									   vk::Allocator&					allocator,
+									   vk::VkImage						image,
+									   const tcu::TextureLevelPyramid&	data)
+{
+	const deUint32						arraySize					= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1) :
+																	  (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * (deUint32)ARRAY_SIZE) :
+																	  ((deUint32)ARRAY_SIZE);
+	const deUint32						dataBufferSize				= getTextureLevelPyramidDataSize(data);
+	const vk::VkBufferCreateInfo		bufferCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		dataBufferSize,										// size
+		vk::VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT,			// usage
+		0u,													// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,						// sharingMode
+		0u,													// queueFamilyCount
+		DE_NULL,											// pQueueFamilyIndices
+	};
+	const vk::Unique<vk::VkBuffer>		dataBuffer					(vk::createBuffer(vki, device, &bufferCreateInfo));
+	const de::MovePtr<vk::Allocation>	dataBufferMemory			= allocateAndBindObjectMemory(vki, device, allocator, *dataBuffer, vk::MemoryRequirement::HostVisible);
+	const vk::VkFenceCreateInfo			fenceCreateInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+		DE_NULL,
+		0u,													// flags
+	};
+	const vk::VkBufferMemoryBarrier		preMemoryBarrier			=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,				// outputMask
+		vk::VK_MEMORY_INPUT_TRANSFER_BIT,					// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
+		*dataBuffer,										// buffer
+		0u,													// offset
+		dataBufferSize,										// size
+	};
+	const vk::VkImageSubresourceRange	fullSubrange				=
+	{
+		vk::VK_IMAGE_ASPECT_COLOR_BIT,						// aspectMask
+		0u,													// baseMipLevel
+		(deUint32)data.getNumLevels(),						// mipLevels
+		0u,													// baseArraySlice
+		arraySize,											// arraySize
+	};
+	const vk::VkImageMemoryBarrier		preImageBarrier				=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+		DE_NULL,
+		0u,													// outputMask
+		0u,													// inputMask
+		vk::VK_IMAGE_LAYOUT_UNDEFINED,						// oldLayout
+		vk::VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,	// newLayout
+		vk::VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
+		image,												// image
+		fullSubrange										// subresourceRange
+	};
+	const vk::VkImageMemoryBarrier		postImageBarrier			=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_TRANSFER_BIT,					// outputMask
+		vk::VK_MEMORY_INPUT_SHADER_READ_BIT,				// inputMask
+		vk::VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,	// oldLayout
+		vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,		// newLayout
+		vk::VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
+		image,												// image
+		fullSubrange										// subresourceRange
+	};
+	const vk::VkCmdPoolCreateInfo		cmdPoolCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
+		DE_NULL,
+		queueFamilyIndex,									// queueFamilyIndex
+		vk::VK_CMD_POOL_CREATE_TRANSIENT_BIT,				// flags
+	};
+	const vk::Unique<vk::VkCmdPool>		cmdPool						(vk::createCommandPool(vki, device, &cmdPoolCreateInfo));
+	const vk::VkCmdBufferCreateInfo		cmdBufCreateInfo			=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		*cmdPool,											// cmdPool
+		vk::VK_CMD_BUFFER_LEVEL_PRIMARY,					// level
+		0u,													// flags
+	};
+	const vk::VkCmdBufferBeginInfo		cmdBufBeginInfo				=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		vk::VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | vk::VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(vk::VkRenderPass)0u,																			// renderPass
+		0u,																								// subpass
+		(vk::VkFramebuffer)0u,																			// framebuffer
+	};
+
+	const vk::Unique<vk::VkCmdBuffer>	cmd							(vk::createCommandBuffer(vki, device, &cmdBufCreateInfo));
+	const void* const					preBarriers[2]				= { &preMemoryBarrier, &preImageBarrier };
+	const void* const					postBarriers[1]				= { &postImageBarrier };
+	const vk::Unique<vk::VkFence>		cmdCompleteFence			(vk::createFence(vki, device, &fenceCreateInfo));
+	const deUint64						infiniteTimeout				= ~(deUint64)0u;
+	std::vector<vk::VkBufferImageCopy>	copySlices;
+
+	// copy data to buffer
+	writeTextureLevelPyramidData(dataBufferMemory->getHostPtr(), dataBufferSize, data, m_viewType , &copySlices);
+	flushMappedMemoryRange(vki, device, dataBufferMemory->getMemory(), dataBufferMemory->getOffset(), dataBufferSize);
+
+	// record command buffer
+	VK_CHECK(vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
+	vki.cmdPipelineBarrier(*cmd, 0u, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_FALSE, DE_LENGTH_OF_ARRAY(preBarriers), preBarriers);
+	vki.cmdCopyBufferToImage(*cmd, *dataBuffer, image, vk::VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, (deUint32)copySlices.size(), &copySlices[0]);
+	vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_FALSE, DE_LENGTH_OF_ARRAY(postBarriers), postBarriers);
+	VK_CHECK(vki.endCommandBuffer(*cmd));
+
+	// submit and wait for command buffer to complete before killing it
+	VK_CHECK(vki.queueSubmit(queue, 1, &cmd.get(), *cmdCompleteFence));
+	VK_CHECK(vki.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
+}
+
+class ImageFetchInstanceImages : private ImageInstanceImages
+{
+public:
+								ImageFetchInstanceImages	(const vk::DeviceInterface&		vki,
+															 vk::VkDevice					device,
+															 deUint32						queueFamilyIndex,
+															 vk::VkQueue					queue,
+															 vk::Allocator&					allocator,
+															 vk::VkDescriptorType			descriptorType,
+															 ShaderInputInterface			shaderInterface,
+															 vk::VkImageViewType			viewType,
+															 deUint32						baseMipLevel,
+															 deUint32						baseArraySlice);
+
+	static tcu::IVec3			getFetchPos					(vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int fetchPosNdx);
+	tcu::Vec4					fetchImageValue				(int fetchPosNdx) const;
+
+	inline vk::VkImageView		getImageViewA				(void) const { return *m_imageViewA; }
+	inline vk::VkImageView		getImageViewB				(void) const { return *m_imageViewB; }
+
+private:
+	enum
+	{
+		// some arbitrary sample points for all four quadrants
+		SAMPLE_POINT_0_X = 6,
+		SAMPLE_POINT_0_Y = 13,
+		SAMPLE_POINT_0_Z = 49,
+
+		SAMPLE_POINT_1_X = 51,
+		SAMPLE_POINT_1_Y = 40,
+		SAMPLE_POINT_1_Z = 44,
+
+		SAMPLE_POINT_2_X = 42,
+		SAMPLE_POINT_2_Y = 26,
+		SAMPLE_POINT_2_Z = 19,
+
+		SAMPLE_POINT_3_X = 25,
+		SAMPLE_POINT_3_Y = 25,
+		SAMPLE_POINT_3_Z = 18,
+	};
+
+	const ShaderInputInterface	m_shaderInterface;
+};
+
+ImageFetchInstanceImages::ImageFetchInstanceImages (const vk::DeviceInterface&	vki,
+													vk::VkDevice				device,
+													deUint32					queueFamilyIndex,
+													vk::VkQueue					queue,
+													vk::Allocator&				allocator,
+													vk::VkDescriptorType		descriptorType,
+													ShaderInputInterface		shaderInterface,
+													vk::VkImageViewType			viewType,
+													deUint32					baseMipLevel,
+													deUint32					baseArraySlice)
+	: ImageInstanceImages	(vki,
+							 device,
+							 queueFamilyIndex,
+							 queue,
+							 allocator,
+							 descriptorType,
+							 viewType,
+							 getInterfaceNumResources(shaderInterface),	// numImages
+							 baseMipLevel,
+							 baseArraySlice)
+	, m_shaderInterface		(shaderInterface)
+{
+}
+
+bool isImageViewTypeArray (vk::VkImageViewType type)
+{
+	return type == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
+}
+
+tcu::IVec3 ImageFetchInstanceImages::getFetchPos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int fetchPosNdx)
+{
+	const tcu::IVec3	fetchPositions[4]	=
+	{
+		tcu::IVec3(SAMPLE_POINT_0_X, SAMPLE_POINT_0_Y, SAMPLE_POINT_0_Z),
+		tcu::IVec3(SAMPLE_POINT_1_X, SAMPLE_POINT_1_Y, SAMPLE_POINT_1_Z),
+		tcu::IVec3(SAMPLE_POINT_2_X, SAMPLE_POINT_2_Y, SAMPLE_POINT_2_Z),
+		tcu::IVec3(SAMPLE_POINT_3_X, SAMPLE_POINT_3_Y, SAMPLE_POINT_3_Z),
+	};
+	const tcu::IVec3	coord				= de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
+	const deUint32		imageSize			= (deUint32)IMAGE_SIZE >> baseMipLevel;
+	const deUint32		arraySize			= isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
+
+	switch (viewType)
+	{
+		case vk::VK_IMAGE_VIEW_TYPE_1D:
+		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % arraySize, 0);
+		case vk::VK_IMAGE_VIEW_TYPE_2D:
+		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % arraySize);
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % (arraySize * 6));
+		case vk::VK_IMAGE_VIEW_TYPE_3D:			return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % imageSize);
+		default:
+			DE_FATAL("Impossible");
+			return tcu::IVec3();
+	}
+}
+
+tcu::Vec4 ImageFetchInstanceImages::fetchImageValue (int fetchPosNdx) const
+{
+	DE_ASSERT(de::inBounds(fetchPosNdx, 0, 4));
+
+	const tcu::TextureLevelPyramid&	fetchSrcA	= m_sourceImageA;
+	const tcu::TextureLevelPyramid&	fetchSrcB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_sourceImageA) : (m_sourceImageB);
+	const tcu::TextureLevelPyramid&	fetchSrc	= ((fetchPosNdx % 2) == 0) ? (fetchSrcA) : (fetchSrcB); // sampling order is ABAB
+	const tcu::IVec3				fetchPos	= getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
+
+	return fetchSrc.getLevel(m_baseMipLevel).getPixel(fetchPos.x(), fetchPos.y(), fetchPos.z());
+}
+
+class ImageFetchRenderInstance : public SingleCmdRenderInstance
+{
+public:
+													ImageFetchRenderInstance	(vkt::Context&			context,
+																				 bool					isPrimaryCmdBuf,
+																				 vk::VkDescriptorType	descriptorType,
+																				 vk::VkShaderStageFlags	stageFlags,
+																				 ShaderInputInterface	shaderInterface,
+																				 vk::VkImageViewType	viewType,
+																				 deUint32				baseMipLevel,
+																				 deUint32				baseArraySlice);
+
+private:
+	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkShaderStageFlags		stageFlags);
+
+	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorSetLayout	descriptorSetLayout);
+
+	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface);
+
+	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkDescriptorSetLayout	layout,
+																				 vk::VkDescriptorPool		pool,
+																				 vk::VkImageView			viewA,
+																				 vk::VkImageView			viewB);
+
+	void											logTestPlan					(void) const;
+	vk::VkPipelineLayout							getPipelineLayout			(void) const;
+	void											writeDrawCmdBuffer			(vk::VkCmdBuffer cmd) const;
+	tcu::TestStatus									verifyResultImage			(const tcu::ConstPixelBufferAccess& result) const;
+
+	enum
+	{
+		RENDER_SIZE = 128,
+	};
+
+	const vk::VkDescriptorType						m_descriptorType;
+	const vk::VkShaderStageFlags					m_stageFlags;
+	const ShaderInputInterface						m_shaderInterface;
+	const vk::VkImageViewType						m_viewType;
+	const deUint32									m_baseMipLevel;
+	const deUint32									m_baseArraySlice;
+
+	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
+	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
+	const ImageFetchInstanceImages					m_images;
+	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
+	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
+};
+
+ImageFetchRenderInstance::ImageFetchRenderInstance	(vkt::Context&			context,
+													 bool					isPrimaryCmdBuf,
+													 vk::VkDescriptorType	descriptorType,
+													 vk::VkShaderStageFlags	stageFlags,
+													 ShaderInputInterface	shaderInterface,
+													 vk::VkImageViewType	viewType,
+													 deUint32				baseMipLevel,
+													 deUint32				baseArraySlice)
+	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
+	, m_descriptorType			(descriptorType)
+	, m_stageFlags				(stageFlags)
+	, m_shaderInterface			(shaderInterface)
+	, m_viewType				(viewType)
+	, m_baseMipLevel			(baseMipLevel)
+	, m_baseArraySlice			(baseArraySlice)
+	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags))
+	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
+	, m_images					(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
+	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
+	, m_descriptorSet			(createDescriptorSet(m_vki, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, m_images.getImageViewA(), m_images.getImageViewB()))
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> ImageFetchRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&		vki,
+																						 vk::VkDevice					device,
+																						 vk::VkDescriptorType			descriptorType,
+																						 ShaderInputInterface			shaderInterface,
+																						 vk::VkShaderStageFlags			stageFlags)
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(descriptorType, 2u, stageFlags);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return builder.build(vki, device);
+}
+
+vk::Move<vk::VkPipelineLayout> ImageFetchRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
+																			   vk::VkDevice					device,
+																			   vk::VkDescriptorSetLayout	descriptorSetLayout)
+{
+	const vk::VkPipelineLayoutCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		1,						// descriptorSetCount
+		&descriptorSetLayout,	// pSetLayouts
+		0u,						// pushConstantRangeCount
+		DE_NULL,				// pPushConstantRanges
+	};
+	return vk::createPipelineLayout(vki, device, &createInfo);
+}
+
+vk::Move<vk::VkDescriptorPool> ImageFetchRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
+																			   vk::VkDevice					device,
+																			   vk::VkDescriptorType			descriptorType,
+																			   ShaderInputInterface			shaderInterface)
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
+		.build(vki, device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> ImageFetchRenderInstance::createDescriptorSet (const vk::DeviceInterface&		vki,
+																			 vk::VkDevice					device,
+																			 vk::VkDescriptorType			descriptorType,
+																			 ShaderInputInterface			shaderInterface,
+																			 vk::VkDescriptorSetLayout		layout,
+																			 vk::VkDescriptorPool			pool,
+																			 vk::VkImageView				viewA,
+																			 vk::VkImageView				viewB)
+{
+	const vk::VkDescriptorInfo		imageInfos[2]	=
+	{
+		createDescriptorInfo(viewA, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+		createDescriptorInfo(viewB, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet	= allocDescriptorSet(vki, device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &imageInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, imageInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(vki, device);
+	return descriptorSet;
+}
+
+void ImageFetchRenderInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Rendering 2x2 grid.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
+		<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
+
+	if (m_baseMipLevel)
+		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
+	if (m_baseArraySlice)
+		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
+
+	if (m_stageFlags == 0u)
+	{
+		msg << "Descriptors are not accessed in any shader stage.\n";
+	}
+	else
+	{
+		msg << "Color in each cell is fetched using the descriptor(s):\n";
+
+		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+		{
+			msg << "Test sample " << resultNdx << ": fetching at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
+
+			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+			{
+				const int srcResourceNdx = (resultNdx % 2); // ABAB source
+				msg << " from descriptor " << srcResourceNdx;
+			}
+
+			msg << "\n";
+		}
+
+		msg << "Descriptors are accessed in {"
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)			? (" vertex")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)		? (" geometry")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)		? (" fragment")			: (""))
+			<< " } stages.";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+vk::VkPipelineLayout ImageFetchRenderInstance::getPipelineLayout (void) const
+{
+	return *m_pipelineLayout;
+}
+
+void ImageFetchRenderInstance::writeDrawCmdBuffer (vk::VkCmdBuffer cmd) const
+{
+	m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
+	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
+}
+
+tcu::TestStatus ImageFetchRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
+{
+	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
+	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
+	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_images.fetchImageValue(0));
+	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_images.fetchImageValue(1));
+	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_images.fetchImageValue(2));
+	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_images.fetchImageValue(3));
+	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
+
+	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
+
+	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
+		return tcu::TestStatus::fail("Image verification failed");
+	else
+		return tcu::TestStatus::pass("Pass");
+}
+
+class ImageFetchComputeInstance : public vkt::TestInstance
+{
+public:
+											ImageFetchComputeInstance	(vkt::Context&			context,
+																		 vk::VkDescriptorType	descriptorType,
+																		 ShaderInputInterface	shaderInterface,
+																		 vk::VkImageViewType	viewType,
+																		 deUint32				baseMipLevel,
+																		 deUint32				baseArraySlice);
+
+private:
+	vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(void) const;
+	vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(void) const;
+	vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const;
+
+	tcu::TestStatus							iterate						(void);
+	void									logTestPlan					(void) const;
+	tcu::TestStatus							testResourceAccess			(void);
+
+	const vk::VkDescriptorType				m_descriptorType;
+	const ShaderInputInterface				m_shaderInterface;
+	const vk::VkImageViewType				m_viewType;
+	const deUint32							m_baseMipLevel;
+	const deUint32							m_baseArraySlice;
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+	const vk::VkQueue						m_queue;
+	const deUint32							m_queueFamilyIndex;
+	vk::Allocator&							m_allocator;
+
+	const ComputeInstanceResultBuffer		m_result;
+	const ImageFetchInstanceImages			m_images;
+};
+
+ImageFetchComputeInstance::ImageFetchComputeInstance (Context&				context,
+													  vk::VkDescriptorType	descriptorType,
+													  ShaderInputInterface	shaderInterface,
+													  vk::VkImageViewType	viewType,
+													  deUint32				baseMipLevel,
+													  deUint32				baseArraySlice)
+	: vkt::TestInstance		(context)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_viewType			(viewType)
+	, m_baseMipLevel		(baseMipLevel)
+	, m_baseArraySlice		(baseArraySlice)
+	, m_vki					(context.getDeviceInterface())
+	, m_device				(context.getDevice())
+	, m_queue				(context.getUniversalQueue())
+	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
+	, m_allocator			(context.getDefaultAllocator())
+	, m_result				(m_vki, m_device, m_allocator)
+	, m_images				(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> ImageFetchComputeInstance::createDescriptorSetLayout (void) const
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	};
+
+	return builder.build(m_vki, m_device);
+}
+
+vk::Move<vk::VkDescriptorPool> ImageFetchComputeInstance::createDescriptorPool (void) const
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
+		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> ImageFetchComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const
+{
+	const vk::VkDescriptorInfo		resultInfo		= createDescriptorInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
+	const vk::VkDescriptorInfo		imageInfos[2]	=
+	{
+		createDescriptorInfo(m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+		createDescriptorInfo(m_images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet	= allocDescriptorSet(m_vki, m_device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// result
+	builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
+
+	// images
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &imageInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &imageInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &imageInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, imageInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(m_vki, m_device);
+	return descriptorSet;
+}
+
+tcu::TestStatus ImageFetchComputeInstance::iterate (void)
+{
+	logTestPlan();
+	return testResourceAccess();
+}
+
+void ImageFetchComputeInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Fetching 4 values from image in compute shader.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
+		<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
+
+	if (m_baseMipLevel)
+		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
+	if (m_baseArraySlice)
+		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
+
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		msg << "Test sample " << resultNdx << ": fetch at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
+
+		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+		{
+			const int srcResourceNdx = (resultNdx % 2); // ABAB source
+			msg << " from descriptor " << srcResourceNdx;
+		}
+
+		msg << "\n";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+tcu::TestStatus ImageFetchComputeInstance::testResourceAccess (void)
+{
+	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
+	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
+	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
+	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
+
+	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
+	const int										numDescriptorSets	= DE_LENGTH_OF_ARRAY(descriptorSets);
+	const deUint32* const							dynamicOffsets		= DE_NULL;
+	const int										numDynamicOffsets	= 0;
+	const void*	const*								preBarriers			= DE_NULL;
+	const int										numPreBarriers		= 0;
+	const void* const								postBarriers[]		= { m_result.getResultReadBarrier() };
+	const int										numPostBarriers		= DE_LENGTH_OF_ARRAY(postBarriers);
+
+	const ComputeCommand							compute				(m_vki,
+																		 m_device,
+																		 pipeline.getPipeline(),
+																		 pipeline.getPipelineLayout(),
+																		 tcu::UVec3(4, 1, 1),
+																		 numDescriptorSets,	descriptorSets,
+																		 numDynamicOffsets,	dynamicOffsets,
+																		 numPreBarriers,	preBarriers,
+																		 numPostBarriers,	postBarriers);
+
+	tcu::Vec4										results[4];
+	bool											anyResultSet		= false;
+	bool											allResultsOk		= true;
+
+	compute.submitAndWait(m_queueFamilyIndex, m_queue);
+	m_result.readResultContentsTo(&results);
+
+	// verify
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		const tcu::Vec4	result				= results[resultNdx];
+		const tcu::Vec4	reference			= m_images.fetchImageValue(resultNdx);
+		const tcu::Vec4	conversionThreshold	= tcu::Vec4(1.0f / 255.0f);
+
+		if (result != tcu::Vec4(-1.0f))
+			anyResultSet = true;
+
+		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
+		{
+			allResultsOk = false;
+
+			m_context.getTestContext().getLog()
+				<< tcu::TestLog::Message
+				<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
+				<< tcu::TestLog::EndMessage;
+		}
+	}
+
+	// read back and verify
+	if (allResultsOk)
+		return tcu::TestStatus::pass("Pass");
+	else if (anyResultSet)
+		return tcu::TestStatus::fail("Invalid result values");
+	else
+	{
+		m_context.getTestContext().getLog()
+			<< tcu::TestLog::Message
+			<< "Result buffer was not written to."
+			<< tcu::TestLog::EndMessage;
+		return tcu::TestStatus::fail("Result buffer was not written to");
+	}
+}
+
+class ImageSampleInstanceImages : private ImageInstanceImages
+{
+public:
+										ImageSampleInstanceImages	(const vk::DeviceInterface&		vki,
+																	 vk::VkDevice					device,
+																	 deUint32						queueFamilyIndex,
+																	 vk::VkQueue					queue,
+																	 vk::Allocator&					allocator,
+																	 vk::VkDescriptorType			descriptorType,
+																	 ShaderInputInterface			shaderInterface,
+																	 vk::VkImageViewType			viewType,
+																	 deUint32						baseMipLevel,
+																	 deUint32						baseArraySlice,
+																	 bool							immutable);
+
+	static tcu::Vec4					getSamplePos				(vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx);
+	tcu::Vec4							fetchSampleValue			(int samplePosNdx) const;
+
+	inline vk::VkImageView				getImageViewA				(void) const { return *m_imageViewA;	}
+	inline vk::VkImageView				getImageViewB				(void) const { return *m_imageViewB;	}
+	inline vk::VkSampler				getSamplerA					(void) const { return *m_samplerA;		}
+	inline vk::VkSampler				getSamplerB					(void) const { return *m_samplerB;		}
+	inline bool							isImmutable					(void) const { return m_isImmutable;	}
+
+private:
+	static int							getNumImages				(vk::VkDescriptorType descriptorType, ShaderInputInterface shaderInterface);
+	static tcu::Sampler					createRefSampler			(bool isFirst);
+	static vk::Move<vk::VkSampler>		createSampler				(const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format);
+
+	static tcu::Texture1DArrayView		getRef1DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
+	static tcu::Texture2DArrayView		getRef2DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
+	static tcu::Texture3DView			getRef3DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
+	static tcu::TextureCubeArrayView	getRefCubeView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
+
+	const vk::VkDescriptorType			m_descriptorType;
+	const ShaderInputInterface			m_shaderInterface;
+	const bool							m_isImmutable;
+
+	const tcu::Sampler					m_refSamplerA;
+	const tcu::Sampler					m_refSamplerB;
+	const vk::Unique<vk::VkSampler>		m_samplerA;
+	const vk::Unique<vk::VkSampler>		m_samplerB;
+};
+
+ImageSampleInstanceImages::ImageSampleInstanceImages (const vk::DeviceInterface&	vki,
+													  vk::VkDevice					device,
+													  deUint32						queueFamilyIndex,
+													  vk::VkQueue					queue,
+													  vk::Allocator&				allocator,
+													  vk::VkDescriptorType			descriptorType,
+													  ShaderInputInterface			shaderInterface,
+													  vk::VkImageViewType			viewType,
+													  deUint32						baseMipLevel,
+													  deUint32						baseArraySlice,
+													  bool							immutable)
+	: ImageInstanceImages	(vki,
+							 device,
+							 queueFamilyIndex,
+							 queue,
+							 allocator,
+							 descriptorType,
+							 viewType,
+							 getNumImages(descriptorType, shaderInterface),
+							 baseMipLevel,
+							 baseArraySlice)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_isImmutable			(immutable)
+	, m_refSamplerA			(createRefSampler(true))
+	, m_refSamplerB			(createRefSampler(false))
+	, m_samplerA			(createSampler(vki, device, m_refSamplerA, m_imageFormat))
+	, m_samplerB			((getInterfaceNumResources(m_shaderInterface) == 1u)
+								? vk::Move<vk::VkSampler>()
+								: createSampler(vki, device, m_refSamplerB, m_imageFormat))
+{
+}
+
+tcu::Vec4 ImageSampleInstanceImages::getSamplePos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx)
+{
+	DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
+
+	const deUint32	imageSize	= (deUint32)IMAGE_SIZE >> baseMipLevel;
+	const deUint32	arraySize	= isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
+
+	// choose arbitrary values that are not ambiguous with NEAREST filtering
+
+	switch (viewType)
+	{
+		case vk::VK_IMAGE_VIEW_TYPE_1D:
+		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:
+		case vk::VK_IMAGE_VIEW_TYPE_2D:
+		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:
+		case vk::VK_IMAGE_VIEW_TYPE_3D:
+		{
+			const tcu::Vec3	coords[4]	=
+			{
+				tcu::Vec3(0.75f,
+						  0.5f,
+						  (float)(12u % imageSize) + 0.25f),
+
+				tcu::Vec3((float)(23u % imageSize) + 0.25f,
+						  (float)(73u % imageSize) + 0.5f,
+						  (float)(16u % imageSize) + 0.5f + (float)imageSize),
+
+				tcu::Vec3(-(float)(43u % imageSize) + 0.25f,
+						  (float)(84u % imageSize) + 0.5f + (float)imageSize,
+						  (float)(117u % imageSize) + 0.75f),
+
+				tcu::Vec3((float)imageSize + 0.5f,
+						  (float)(75u % imageSize) + 0.25f,
+						  (float)(83u % imageSize) + 0.25f + (float)imageSize),
+			};
+			const deUint32	slices[4]	=
+			{
+				0u % arraySize,
+				4u % arraySize,
+				9u % arraySize,
+				2u % arraySize,
+			};
+
+			if (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)
+				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
+								 (float)slices[samplePosNdx],
+								 0.0f,
+								 0.0f);
+			else if (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)
+				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
+								 coords[samplePosNdx].y() / (float)imageSize,
+								 (float)slices[samplePosNdx],
+								 0.0f);
+			else if (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)
+				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
+								 coords[samplePosNdx].y() / (float)imageSize,
+								 coords[samplePosNdx].z() / (float)imageSize,
+								 0.0f);
+			else
+			{
+				DE_FATAL("Impossible");
+				return tcu::Vec4();
+			}
+		}
+
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
+		{
+			// \note these values are in [0, texSize]*3 space for convenience
+			const tcu::Vec3	coords[4]	=
+			{
+				tcu::Vec3(0.75f,
+						  0.5f,
+						  (float)imageSize),
+
+				tcu::Vec3((float)(13u % imageSize) + 0.25f,
+						  0.0f,
+						  (float)(16u % imageSize) + 0.5f),
+
+				tcu::Vec3(0.0f,
+						  (float)(84u % imageSize) + 0.5f,
+						  (float)(10u % imageSize) + 0.75f),
+
+				tcu::Vec3((float)imageSize,
+						  (float)(75u % imageSize) + 0.25f,
+						  (float)(83u % imageSize) + 0.75f),
+			};
+			const deUint32	slices[4]	=
+			{
+				1u % arraySize,
+				2u % arraySize,
+				9u % arraySize,
+				5u % arraySize,
+			};
+
+			DE_ASSERT(de::inRange(coords[samplePosNdx].x(), 0.0f, (float)imageSize));
+			DE_ASSERT(de::inRange(coords[samplePosNdx].y(), 0.0f, (float)imageSize));
+			DE_ASSERT(de::inRange(coords[samplePosNdx].z(), 0.0f, (float)imageSize));
+
+			// map to [-1, 1]*3 space
+			return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize * 2.0f - 1.0f,
+							 coords[samplePosNdx].y() / (float)imageSize * 2.0f - 1.0f,
+							 coords[samplePosNdx].z() / (float)imageSize * 2.0f - 1.0f,
+							 (float)slices[samplePosNdx]);
+		}
+
+		default:
+			DE_FATAL("Impossible");
+			return tcu::Vec4();
+	}
+}
+
+tcu::Vec4 ImageSampleInstanceImages::fetchSampleValue (int samplePosNdx) const
+{
+	DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
+
+	// texture order is ABAB
+	const bool									isSamplerCase	= (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER);
+	const tcu::TextureLevelPyramid&				sampleSrcA		= m_sourceImageA;
+	const tcu::TextureLevelPyramid&				sampleSrcB		= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_sourceImageA) : (m_sourceImageB);
+	const tcu::TextureLevelPyramid&				sampleSrc		= (isSamplerCase) ? (sampleSrcA) : ((samplePosNdx % 2) == 0) ? (sampleSrcA) : (sampleSrcB);
+
+	// sampler order is ABAB
+	const tcu::Sampler&							samplerA		= m_refSamplerA;
+	const tcu::Sampler&							samplerB		= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_refSamplerA) : (m_refSamplerB);
+	const tcu::Sampler&							sampler			= ((samplePosNdx % 2) == 0) ? (samplerA) : (samplerB);
+
+	const tcu::Vec4								samplePos		= getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
+	const float									lod				= 0.0f;
+	std::vector<tcu::ConstPixelBufferAccess>	levelStorage;
+
+	switch (m_viewType)
+	{
+		case vk::VK_IMAGE_VIEW_TYPE_1D:
+		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return getRef1DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), lod);
+		case vk::VK_IMAGE_VIEW_TYPE_2D:
+		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return getRef2DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
+		case vk::VK_IMAGE_VIEW_TYPE_3D:			return getRef3DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
+		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return getRefCubeView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), samplePos.w(), lod);
+
+		default:
+		{
+			DE_FATAL("Impossible");
+			return tcu::Vec4();
+		}
+	}
+}
+
+int ImageSampleInstanceImages::getNumImages (vk::VkDescriptorType descriptorType, ShaderInputInterface shaderInterface)
+{
+	// If we are testing separate samplers, just one image is enough
+	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		return 1;
+	else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+	{
+		// combined: numImages == numSamplers
+		return getInterfaceNumResources(shaderInterface);
+	}
+	else
+	{
+		DE_FATAL("Impossible");
+		return 0;
+	}
+}
+
+tcu::Sampler ImageSampleInstanceImages::createRefSampler (bool isFirst)
+{
+	if (isFirst)
+	{
+		// linear, wrapping
+		return tcu::Sampler(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
+	}
+	else
+	{
+		// nearest, clamping
+		return tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
+	}
+}
+
+vk::Move<vk::VkSampler> ImageSampleInstanceImages::createSampler (const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format)
+{
+	const bool						compareEnabled	= (sampler.compare != tcu::Sampler::COMPAREMODE_NONE);
+	const vk::VkCompareOp			compareOp		= (compareEnabled) ? (mapToVkCompareOp(sampler.compare)) : (vk::VK_COMPARE_OP_ALWAYS);
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+	const bool						isIntTexture	= channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
+	const vk::VkBorderColor			borderColor		= (isIntTexture) ? (vk::VK_BORDER_COLOR_INT_OPAQUE_WHITE) : (vk::VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE);
+	const vk::VkSamplerCreateInfo	createInfo		=
+	{
+		vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+		DE_NULL,
+		mapMagFilterToVkTexFilter(sampler.magFilter),									// magFilter
+		mapMinFilterToVkTexFilter(sampler.minFilter),									// minFilter
+		mapMinFilterToVkTexMipmapMode(sampler.minFilter),								// mipMode
+		mapToVkTexAddressMode(sampler.wrapS),											// addressU
+		mapToVkTexAddressMode(sampler.wrapT),											// addressV
+		mapToVkTexAddressMode(sampler.wrapR),											// addressW
+		0.0f,																			// mipLodBias
+		1,																				// maxAnisotropy
+		(compareEnabled) ? (vk::VkBool32)(vk::VK_TRUE) : (vk::VkBool32)(vk::VK_FALSE),	// compareEnable
+		compareOp,																		// compareOp
+		0.0f,																			// minLod
+		0.0f,																			// maxLod
+		borderColor,																	// borderColor
+		vk::VK_FALSE,																	// unnormalizedCoords
+	};
+	return vk::createSampler(vki, device, &createInfo);
+}
+
+tcu::Texture1DArrayView ImageSampleInstanceImages::getRef1DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
+{
+	DE_ASSERT(levelStorage->empty());
+
+	const deUint32 numSlices = (deUint32)source.getLevel(0).getHeight();
+	const deUint32 numLevels = (deUint32)source.getNumLevels();
+
+	// cut pyramid from baseMipLevel
+	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
+	{
+		// cut levels from baseArraySlice
+		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
+		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, baseArraySlice, wholeLevel.getWidth(), numSlices - baseArraySlice);
+		levelStorage->push_back(cutLevel);
+	}
+
+	return tcu::Texture1DArrayView((int)levelStorage->size(), &levelStorage->front());
+}
+
+tcu::Texture2DArrayView ImageSampleInstanceImages::getRef2DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
+{
+	DE_ASSERT(levelStorage->empty());
+
+	const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth();
+	const deUint32 numLevels = (deUint32)source.getNumLevels();
+
+	// cut pyramid from baseMipLevel
+	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
+	{
+		// cut levels from baseArraySlice
+		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
+		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice, wholeLevel.getWidth(), wholeLevel.getHeight(), numSlices - baseArraySlice);
+		levelStorage->push_back(cutLevel);
+	}
+
+	return tcu::Texture2DArrayView((int)levelStorage->size(), &levelStorage->front());
+}
+
+tcu::Texture3DView ImageSampleInstanceImages::getRef3DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
+{
+	DE_ASSERT(levelStorage->empty());
+	DE_ASSERT(baseArraySlice == 0);
+	DE_UNREF(baseArraySlice);
+
+	const deUint32 numLevels = (deUint32)source.getNumLevels();
+
+	// cut pyramid from baseMipLevel
+	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
+		levelStorage->push_back(source.getLevel(level));
+
+	return tcu::Texture3DView((int)levelStorage->size(), &levelStorage->front());
+}
+
+tcu::TextureCubeArrayView ImageSampleInstanceImages::getRefCubeView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
+{
+	DE_ASSERT(levelStorage->empty());
+
+	const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth() / 6;
+	const deUint32 numLevels = (deUint32)source.getNumLevels();
+
+	// cut pyramid from baseMipLevel
+	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
+	{
+		// cut levels from baseArraySlice
+		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
+		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice * 6, wholeLevel.getWidth(), wholeLevel.getHeight(), (numSlices - baseArraySlice) * 6);
+		levelStorage->push_back(cutLevel);
+	}
+
+	return tcu::TextureCubeArrayView((int)levelStorage->size(), &levelStorage->front());
+}
+
+class ImageSampleRenderInstance : public SingleCmdRenderInstance
+{
+public:
+													ImageSampleRenderInstance		(vkt::Context&			context,
+																					 bool					isPrimaryCmdBuf,
+																					 vk::VkDescriptorType	descriptorType,
+																					 vk::VkShaderStageFlags	stageFlags,
+																					 ShaderInputInterface	shaderInterface,
+																					 vk::VkImageViewType	viewType,
+																					 deUint32				baseMipLevel,
+																					 deUint32				baseArraySlice,
+																					 bool					isImmutable);
+
+private:
+	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout		(const vk::DeviceInterface&			vki,
+																					 vk::VkDevice						device,
+																					 vk::VkDescriptorType				descriptorType,
+																					 ShaderInputInterface				shaderInterface,
+																					 vk::VkShaderStageFlags				stageFlags,
+																					 const ImageSampleInstanceImages&	images);
+
+	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout			(const vk::DeviceInterface&	vki,
+																					 vk::VkDevice				device,
+																					 vk::VkDescriptorSetLayout	descriptorSetLayout);
+
+	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool			(const vk::DeviceInterface&	vki,
+																					 vk::VkDevice				device,
+																					 vk::VkDescriptorType		descriptorType,
+																					 ShaderInputInterface		shaderInterface,
+																					 bool						isImmutable);
+
+	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet				(const vk::DeviceInterface&			vki,
+																					 vk::VkDevice						device,
+																					 vk::VkDescriptorType				descriptorType,
+																					 ShaderInputInterface				shaderInterface,
+																					 vk::VkDescriptorSetLayout			layout,
+																					 vk::VkDescriptorPool				pool,
+																					 bool								isImmutable,
+																					 const ImageSampleInstanceImages&	images);
+
+	static void										writeSamplerDescriptorSet		(const vk::DeviceInterface&			vki,
+																					 vk::VkDevice						device,
+																					 ShaderInputInterface				shaderInterface,
+																					 bool								isImmutable,
+																					 const ImageSampleInstanceImages&	images,
+																					 vk::VkDescriptorSet				descriptorSet);
+
+	static void										writeImageSamplerDescriptorSet	(const vk::DeviceInterface&			vki,
+																					 vk::VkDevice						device,
+																					 ShaderInputInterface				shaderInterface,
+																					 bool								isImmutable,
+																					 const ImageSampleInstanceImages&	images,
+																					 vk::VkDescriptorSet				descriptorSet);
+
+	void											logTestPlan						(void) const;
+	vk::VkPipelineLayout							getPipelineLayout				(void) const;
+	void											writeDrawCmdBuffer				(vk::VkCmdBuffer cmd) const;
+	tcu::TestStatus									verifyResultImage				(const tcu::ConstPixelBufferAccess& result) const;
+
+	enum
+	{
+		RENDER_SIZE = 128,
+	};
+
+	const vk::VkDescriptorType						m_descriptorType;
+	const vk::VkShaderStageFlags					m_stageFlags;
+	const ShaderInputInterface						m_shaderInterface;
+	const vk::VkImageViewType						m_viewType;
+	const deUint32									m_baseMipLevel;
+	const deUint32									m_baseArraySlice;
+
+	const ImageSampleInstanceImages					m_images;
+	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
+	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
+	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
+	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
+};
+
+ImageSampleRenderInstance::ImageSampleRenderInstance (vkt::Context&				context,
+													  bool						isPrimaryCmdBuf,
+													  vk::VkDescriptorType		descriptorType,
+													  vk::VkShaderStageFlags	stageFlags,
+													  ShaderInputInterface		shaderInterface,
+													  vk::VkImageViewType		viewType,
+													  deUint32					baseMipLevel,
+													  deUint32					baseArraySlice,
+													  bool						isImmutable)
+	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
+	, m_descriptorType			(descriptorType)
+	, m_stageFlags				(stageFlags)
+	, m_shaderInterface			(shaderInterface)
+	, m_viewType				(viewType)
+	, m_baseMipLevel			(baseMipLevel)
+	, m_baseArraySlice			(baseArraySlice)
+	, m_images					(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutable)
+	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags, m_images))
+	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
+	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface, isImmutable))
+	, m_descriptorSet			(createDescriptorSet(m_vki, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, isImmutable, m_images))
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> ImageSampleRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&		vki,
+																						  vk::VkDevice						device,
+																						  vk::VkDescriptorType				descriptorType,
+																						  ShaderInputInterface				shaderInterface,
+																						  vk::VkShaderStageFlags			stageFlags,
+																						  const ImageSampleInstanceImages&	images)
+{
+	const vk::VkSampler				samplers[2] =
+	{
+		images.getSamplerA(),
+		images.getSamplerB(),
+	};
+
+	vk::DescriptorSetLayoutBuilder	builder;
+
+	// with samplers, separate texture at binding 0
+	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
+
+	// (combined)samplers follow
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
+			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArraySamplerBinding(descriptorType, 2u, stageFlags, (images.isImmutable()) ? (samplers) : (DE_NULL));
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return builder.build(vki, device);
+}
+
+vk::Move<vk::VkPipelineLayout> ImageSampleRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
+																				vk::VkDevice				device,
+																				vk::VkDescriptorSetLayout	descriptorSetLayout)
+{
+	const vk::VkPipelineLayoutCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		1,						// descriptorSetCount
+		&descriptorSetLayout,	// pSetLayouts
+		0u,						// pushConstantRangeCount
+		DE_NULL,				// pPushConstantRanges
+	};
+	return vk::createPipelineLayout(vki, device, &createInfo);
+}
+
+vk::Move<vk::VkDescriptorPool> ImageSampleRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
+																				vk::VkDevice				device,
+																				vk::VkDescriptorType		descriptorType,
+																				ShaderInputInterface		shaderInterface,
+																				bool						isImmutable)
+{
+	vk::DescriptorPoolBuilder builder;
+
+	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+	{
+		// separate samplers need image to sample
+		builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
+
+		// samplers needed only if they are specified in the descriptor set
+		if (!isImmutable)
+			builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLER, getInterfaceNumResources(shaderInterface));
+	}
+	else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+	{
+		// combined image samplers
+		builder.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, getInterfaceNumResources(shaderInterface));
+	}
+	else
+		DE_FATAL("Impossible");
+
+	return builder.build(vki, device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> ImageSampleRenderInstance::createDescriptorSet (const vk::DeviceInterface&		vki,
+																			  vk::VkDevice						device,
+																			  vk::VkDescriptorType				descriptorType,
+																			  ShaderInputInterface				shaderInterface,
+																			  vk::VkDescriptorSetLayout			layout,
+																			  vk::VkDescriptorPool				pool,
+																			  bool								isImmutable,
+																			  const ImageSampleInstanceImages&	images)
+{
+	vk::Move<vk::VkDescriptorSet> descriptorSet = allocDescriptorSet(vki, device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+
+	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		writeSamplerDescriptorSet(vki, device,  shaderInterface, isImmutable, images, *descriptorSet);
+	else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+		writeImageSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet);
+	else
+		DE_FATAL("Impossible");
+
+	return descriptorSet;
+}
+
+void ImageSampleRenderInstance::writeSamplerDescriptorSet (const vk::DeviceInterface&		vki,
+														   vk::VkDevice						device,
+														   ShaderInputInterface				shaderInterface,
+														   bool								isImmutable,
+														   const ImageSampleInstanceImages&	images,
+														   vk::VkDescriptorSet				descriptorSet)
+{
+	const vk::VkDescriptorInfo		imageInfo			= createDescriptorInfo(images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+	const vk::VkDescriptorInfo		samplersInfos[2]	=
+	{
+		createDescriptorInfo(images.getSamplerA()),
+		createDescriptorInfo(images.getSamplerB()),
+	};
+
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// stand alone texture
+	builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
+
+	// samplers
+	if (!isImmutable)
+	{
+		switch (shaderInterface)
+		{
+			case SHADER_INPUT_SINGLE_DESCRIPTOR:
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
+				break;
+
+			case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
+				break;
+
+			case SHADER_INPUT_DESCRIPTOR_ARRAY:
+				builder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
+				break;
+
+			default:
+				DE_FATAL("Impossible");
+		}
+	}
+
+	builder.update(vki, device);
+}
+
+void ImageSampleRenderInstance::writeImageSamplerDescriptorSet (const vk::DeviceInterface&			vki,
+																vk::VkDevice						device,
+																ShaderInputInterface				shaderInterface,
+																bool								isImmutable,
+																const ImageSampleInstanceImages&	images,
+																vk::VkDescriptorSet					descriptorSet)
+{
+	const vk::VkSampler				samplers[2]			=
+	{
+		(isImmutable) ? (0) : (images.getSamplerA()),
+		(isImmutable) ? (0) : (images.getSamplerB()),
+	};
+	const vk::VkDescriptorInfo		imageSamplers[2]	=
+	{
+		createDescriptorInfo(samplers[0], images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+		createDescriptorInfo(samplers[1], images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+	};
+
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// combined image samplers
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(vki, device);
+}
+
+void ImageSampleRenderInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Rendering 2x2 grid.\n";
+
+	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+	{
+		msg << "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+			<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
+	}
+	else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+	{
+		msg << "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+			<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
+	}
+	else
+		DE_FATAL("Impossible");
+
+	msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
+
+	if (m_baseMipLevel)
+		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
+	if (m_baseArraySlice)
+		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
+
+	if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
+		msg << "Sampler mode is LINEAR, with WRAP\n";
+	else
+		msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
+
+	if (m_stageFlags == 0u)
+	{
+		msg << "Descriptors are not accessed in any shader stage.\n";
+	}
+	else
+	{
+		msg << "Color in each cell is fetched using the descriptor(s):\n";
+
+		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+		{
+			msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
+
+			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+			{
+				const int srcResourceNdx = (resultNdx % 2); // ABAB source
+
+				if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+					msg << " using sampler " << srcResourceNdx;
+				else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+					msg << " from combined image sampler " << srcResourceNdx;
+				else
+					DE_FATAL("Impossible");
+			}
+			msg << "\n";
+		}
+
+		msg << "Descriptors are accessed in {"
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)			? (" vertex")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)		? (" geometry")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)		? (" fragment")			: (""))
+			<< " } stages.";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+vk::VkPipelineLayout ImageSampleRenderInstance::getPipelineLayout (void) const
+{
+	return *m_pipelineLayout;
+}
+
+void ImageSampleRenderInstance::writeDrawCmdBuffer (vk::VkCmdBuffer cmd) const
+{
+	m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
+	m_vki.cmdDraw(cmd, 6u * 4u, 1u, 0u, 0u); // render four quads (two separate triangles)
+}
+
+tcu::TestStatus ImageSampleRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
+{
+	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
+	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
+	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_images.fetchSampleValue(0));
+	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_images.fetchSampleValue(1));
+	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_images.fetchSampleValue(2));
+	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_images.fetchSampleValue(3));
+	const tcu::RGBA		threshold	= tcu::RGBA(8, 8, 8, 8); // source image is high-frequency so the threshold is quite large to tolerate sampling errors
+	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
+
+	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
+
+	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, threshold, tcu::COMPARE_LOG_RESULT))
+		return tcu::TestStatus::fail("Image verification failed");
+	else
+		return tcu::TestStatus::pass("Pass");
+}
+
+class ImageSampleComputeInstance : public vkt::TestInstance
+{
+public:
+											ImageSampleComputeInstance		(vkt::Context&			context,
+																			 vk::VkDescriptorType	descriptorType,
+																			 ShaderInputInterface	shaderInterface,
+																			 vk::VkImageViewType	viewType,
+																			 deUint32				baseMipLevel,
+																			 deUint32				baseArraySlice,
+																			 bool					isImmutableSampler);
+
+private:
+	vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout		(void) const;
+	vk::Move<vk::VkDescriptorPool>			createDescriptorPool			(void) const;
+	vk::Move<vk::VkDescriptorSet>			createDescriptorSet				(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const;
+	void									writeImageSamplerDescriptorSet	(vk::VkDescriptorSet descriptorSet) const;
+	void									writeSamplerDescriptorSet		(vk::VkDescriptorSet descriptorSet) const;
+
+	tcu::TestStatus							iterate							(void);
+	void									logTestPlan						(void) const;
+	tcu::TestStatus							testResourceAccess				(void);
+
+	const vk::VkDescriptorType				m_descriptorType;
+	const ShaderInputInterface				m_shaderInterface;
+	const vk::VkImageViewType				m_viewType;
+	const deUint32							m_baseMipLevel;
+	const deUint32							m_baseArraySlice;
+	const bool								m_isImmutableSampler;
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+	const vk::VkQueue						m_queue;
+	const deUint32							m_queueFamilyIndex;
+	vk::Allocator&							m_allocator;
+
+	const ComputeInstanceResultBuffer		m_result;
+	const ImageSampleInstanceImages			m_images;
+};
+
+ImageSampleComputeInstance::ImageSampleComputeInstance (Context&				context,
+														vk::VkDescriptorType	descriptorType,
+														ShaderInputInterface	shaderInterface,
+														vk::VkImageViewType		viewType,
+														deUint32				baseMipLevel,
+														deUint32				baseArraySlice,
+														bool					isImmutableSampler)
+	: vkt::TestInstance		(context)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_viewType			(viewType)
+	, m_baseMipLevel		(baseMipLevel)
+	, m_baseArraySlice		(baseArraySlice)
+	, m_isImmutableSampler	(isImmutableSampler)
+	, m_vki					(context.getDeviceInterface())
+	, m_device				(context.getDevice())
+	, m_queue				(context.getUniversalQueue())
+	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
+	, m_allocator			(context.getDefaultAllocator())
+	, m_result				(m_vki, m_device, m_allocator)
+	, m_images				(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutableSampler)
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> ImageSampleComputeInstance::createDescriptorSetLayout (void) const
+{
+	const vk::VkSampler				samplers[2] =
+	{
+		m_images.getSamplerA(),
+		m_images.getSamplerB(),
+	};
+
+	vk::DescriptorSetLayoutBuilder	builder;
+
+	// result buffer
+	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+
+	// with samplers, separate texture at binding 0
+	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+
+	// (combined)samplers follow
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
+			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArraySamplerBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (samplers) : (DE_NULL));
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	};
+
+	return builder.build(m_vki, m_device);
+}
+
+vk::Move<vk::VkDescriptorPool> ImageSampleComputeInstance::createDescriptorPool (void) const
+{
+	vk::DescriptorPoolBuilder builder;
+
+	builder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+	builder.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface));
+
+	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
+
+	return builder.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> ImageSampleComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const
+{
+	vk::Move<vk::VkDescriptorSet> descriptorSet = allocDescriptorSet(m_vki, m_device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+
+	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+		writeSamplerDescriptorSet(*descriptorSet);
+	else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+		writeImageSamplerDescriptorSet(*descriptorSet);
+	else
+		DE_FATAL("Impossible");
+
+	return descriptorSet;
+}
+
+void ImageSampleComputeInstance::writeSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet) const
+{
+	const vk::VkDescriptorInfo		resultInfo			= createDescriptorInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
+	const vk::VkDescriptorInfo		imageInfo			= createDescriptorInfo(m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+	const vk::VkDescriptorInfo		samplersInfos[2]	=
+	{
+		createDescriptorInfo(m_images.getSamplerA()),
+		createDescriptorInfo(m_images.getSamplerB()),
+	};
+
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// result
+	builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
+
+	// stand alone texture
+	builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
+
+	// samplers
+	if (!m_isImmutableSampler)
+	{
+		switch (m_shaderInterface)
+		{
+			case SHADER_INPUT_SINGLE_DESCRIPTOR:
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
+				break;
+
+			case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
+				builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(3u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
+				break;
+
+			case SHADER_INPUT_DESCRIPTOR_ARRAY:
+				builder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
+				break;
+
+			default:
+				DE_FATAL("Impossible");
+		}
+	}
+
+	builder.update(m_vki, m_device);
+}
+
+void ImageSampleComputeInstance::writeImageSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet) const
+{
+	const vk::VkDescriptorInfo		resultInfo			= createDescriptorInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
+	const vk::VkSampler				samplers[2]			=
+	{
+		(m_isImmutableSampler) ? (0) : (m_images.getSamplerA()),
+		(m_isImmutableSampler) ? (0) : (m_images.getSamplerB()),
+	};
+	const vk::VkDescriptorInfo		imageSamplers[2]	=
+	{
+		createDescriptorInfo(samplers[0], m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+		createDescriptorInfo(samplers[1], m_images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
+	};
+
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// result
+	builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
+
+	// combined image samplers
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
+			builder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(m_vki, m_device);
+}
+
+tcu::TestStatus ImageSampleComputeInstance::iterate (void)
+{
+	logTestPlan();
+	return testResourceAccess();
+}
+
+void ImageSampleComputeInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Accessing resource in a compute program.\n";
+
+	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+	{
+		msg << "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+			<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
+	}
+	else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+	{
+		msg << "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+			<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
+	}
+	else
+		DE_FATAL("Impossible");
+
+	msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
+
+	if (m_baseMipLevel)
+		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
+	if (m_baseArraySlice)
+		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
+
+	if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
+		msg << "Sampler mode is LINEAR, with WRAP\n";
+	else
+		msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
+
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
+
+		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+		{
+			const int srcResourceNdx = (resultNdx % 2); // ABAB source
+
+			if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+				msg << " using sampler " << srcResourceNdx;
+			else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+				msg << " from combined image sampler " << srcResourceNdx;
+			else
+				DE_FATAL("Impossible");
+		}
+		msg << "\n";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+tcu::TestStatus ImageSampleComputeInstance::testResourceAccess (void)
+{
+	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
+	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
+	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
+	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
+
+	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
+	const int										numDescriptorSets	= DE_LENGTH_OF_ARRAY(descriptorSets);
+	const deUint32* const							dynamicOffsets		= DE_NULL;
+	const int										numDynamicOffsets	= 0;
+	const void*	const*								preBarriers			= DE_NULL;
+	const int										numPreBarriers		= 0;
+	const void* const								postBarriers[]		= { m_result.getResultReadBarrier() };
+	const int										numPostBarriers		= DE_LENGTH_OF_ARRAY(postBarriers);
+
+	const ComputeCommand							compute				(m_vki,
+																		 m_device,
+																		 pipeline.getPipeline(),
+																		 pipeline.getPipelineLayout(),
+																		 tcu::UVec3(4, 1, 1),
+																		 numDescriptorSets,	descriptorSets,
+																		 numDynamicOffsets,	dynamicOffsets,
+																		 numPreBarriers,	preBarriers,
+																		 numPostBarriers,	postBarriers);
+
+	tcu::Vec4										results[4];
+	bool											anyResultSet		= false;
+	bool											allResultsOk		= true;
+
+	compute.submitAndWait(m_queueFamilyIndex, m_queue);
+	m_result.readResultContentsTo(&results);
+
+	// verify
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		const tcu::Vec4	result				= results[resultNdx];
+		const tcu::Vec4	reference			= m_images.fetchSampleValue(resultNdx);
+
+		// source image is high-frequency so the threshold is quite large to tolerate sampling errors
+		const tcu::Vec4	samplingThreshold	= tcu::Vec4(8.0f / 255.0f);
+
+		if (result != tcu::Vec4(-1.0f))
+			anyResultSet = true;
+
+		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), samplingThreshold)))
+		{
+			allResultsOk = false;
+
+			m_context.getTestContext().getLog()
+				<< tcu::TestLog::Message
+				<< "Test sample " << resultNdx << ":\n"
+				<< "\tSampling at " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx) << "\n"
+				<< "\tError expected " << reference << ", got " << result
+				<< tcu::TestLog::EndMessage;
+		}
+	}
+
+	// read back and verify
+	if (allResultsOk)
+		return tcu::TestStatus::pass("Pass");
+	else if (anyResultSet)
+		return tcu::TestStatus::fail("Invalid result values");
+	else
+	{
+		m_context.getTestContext().getLog()
+			<< tcu::TestLog::Message
+			<< "Result buffer was not written to."
+			<< tcu::TestLog::EndMessage;
+		return tcu::TestStatus::fail("Result buffer was not written to");
+	}
+}
+
+class ImageDescriptorCase : public QuadrantRendederCase
+{
+public:
+	enum
+	{
+		FLAG_BASE_MIP	= (1u << 1u),
+		FLAG_BASE_SLICE	= (1u << 2u),
+	};
+	// enum continues where resource flags ends
+	DE_STATIC_ASSERT((deUint32)FLAG_BASE_MIP == (deUint32)RESOURCE_FLAG_LAST);
+
+								ImageDescriptorCase			(tcu::TestContext&		testCtx,
+															 const char*			name,
+															 const char*			description,
+															 bool					isPrimaryCmdBuf,
+															 vk::VkDescriptorType	descriptorType,
+															 vk::VkShaderStageFlags	exitingStages,
+															 vk::VkShaderStageFlags	activeStages,
+															 ShaderInputInterface	shaderInterface,
+															 vk::VkImageViewType	viewType,
+															 deUint32				flags);
+
+private:
+	std::string					genExtensionDeclarations	(vk::VkShaderStage stage) const;
+	std::string					genResourceDeclarations		(vk::VkShaderStage stage, int numUsedBindings) const;
+	std::string					genFetchCoordStr			(int fetchPosNdx) const;
+	std::string					genSampleCoordStr			(int samplePosNdx) const;
+	std::string					genResourceAccessSource		(vk::VkShaderStage stage) const;
+	std::string					genNoAccessSource			(void) const;
+
+	vkt::TestInstance*			createInstance				(vkt::Context& context) const;
+
+private:
+	const bool					m_isPrimaryCmdBuf;
+	const vk::VkDescriptorType	m_descriptorType;
+	const ShaderInputInterface	m_shaderInterface;
+	const vk::VkImageViewType	m_viewType;
+	const deUint32				m_baseMipLevel;
+	const deUint32				m_baseArraySlice;
+	const bool					m_isImmutableSampler;
+};
+
+ImageDescriptorCase::ImageDescriptorCase (tcu::TestContext&			testCtx,
+										  const char*				name,
+										  const char*				description,
+										  bool						isPrimaryCmdBuf,
+										  vk::VkDescriptorType		descriptorType,
+										  vk::VkShaderStageFlags	exitingStages,
+										  vk::VkShaderStageFlags	activeStages,
+										  ShaderInputInterface		shaderInterface,
+										  vk::VkImageViewType		viewType,
+										  deUint32					flags)
+	: QuadrantRendederCase	(testCtx, name, description,
+							 // \note 1D textures are not supported in ES
+							 (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? glu::GLSL_VERSION_440 : glu::GLSL_VERSION_310_ES,
+							 exitingStages, activeStages)
+	, m_isPrimaryCmdBuf		(isPrimaryCmdBuf)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_viewType			(viewType)
+	, m_baseMipLevel		(((flags & FLAG_BASE_MIP) != 0) ? (1u) : (0u))
+	, m_baseArraySlice		(((flags & FLAG_BASE_SLICE) != 0) ? (1u) : (0u))
+	, m_isImmutableSampler	((flags & RESOURCE_FLAG_IMMUTABLE_SAMPLER) != 0)
+{
+}
+
+std::string ImageDescriptorCase::genExtensionDeclarations (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+
+	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
+		return "#extension GL_OES_texture_cube_map_array : require\n";
+	else
+		return "";
+}
+
+std::string ImageDescriptorCase::genResourceDeclarations (vk::VkShaderStage stage, int numUsedBindings) const
+{
+	DE_UNREF(stage);
+
+	// Vulkan-style resources are arrays implicitly, OpenGL-style are not
+	const std::string	dimensionBase	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? ("1D")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? ("2D")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? ("3D")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("Cube")
+										: (DE_NULL);
+	const std::string	dimensionArray	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? ("1DArray")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? ("2DArray")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? ("3D")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("CubeArray")
+										: (DE_NULL);
+	const std::string	dimension		= isImageViewTypeArray(m_viewType) ? dimensionArray : dimensionBase;
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+		{
+			switch (m_descriptorType)
+			{
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSampler;\n";
+				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler;\n";
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture;\n";
+				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_image;\n";
+				default:
+					DE_FATAL("invalid descriptor");
+					return "";
+			}
+		}
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			switch (m_descriptorType)
+			{
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSamplerA;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+2) + ") uniform highp sampler u_separateSamplerB;\n";
+				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSamplerA;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler" + dimension + " u_combinedTextureSamplerB;\n";
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTextureA;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp texture" + dimensionBase + " u_separateTextureB;\n";
+				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_imageA;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ", rgba8) readonly uniform highp image" + dimension + " u_imageB;\n";
+				default:
+					DE_FATAL("invalid descriptor");
+					return "";
+			}
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			switch (m_descriptorType)
+			{
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture;\n"
+						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSamplers[2];\n";
+				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler[2];\n";
+				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture[2];\n";
+				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_image[2];\n";
+				default:
+					DE_FATAL("invalid descriptor");
+					return "";
+			}
+
+		default:
+			DE_FATAL("Impossible");
+			return "";
+	}
+}
+
+std::string ImageDescriptorCase::genFetchCoordStr (int fetchPosNdx) const
+{
+	DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
+	const tcu::IVec3 fetchPos = ImageFetchInstanceImages::getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
+
+	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
+	{
+		return de::toString(fetchPos.x());
+	}
+	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
+	{
+		std::ostringstream buf;
+		buf << "ivec2(" << fetchPos.x() << ", " << fetchPos.y() << ")";
+		return buf.str();
+	}
+	else
+	{
+		std::ostringstream buf;
+		buf << "ivec3(" << fetchPos.x() << ", " << fetchPos.y() << ", " << fetchPos.z() << ")";
+		return buf.str();
+	}
+}
+
+std::string ImageDescriptorCase::genSampleCoordStr (int samplePosNdx) const
+{
+	DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
+	const tcu::Vec4 fetchPos = ImageSampleInstanceImages::getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
+
+	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
+	{
+		std::ostringstream buf;
+		buf << "float(" << fetchPos.x() << ")";
+		return buf.str();
+	}
+	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
+	{
+		std::ostringstream buf;
+		buf << "vec2(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "))";
+		return buf.str();
+	}
+	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
+	{
+		std::ostringstream buf;
+		buf << "vec4(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "), float(" << fetchPos.w() << "))";
+		return buf.str();
+	}
+	else
+	{
+		std::ostringstream buf;
+		buf << "vec3(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "))";
+		return buf.str();
+	}
+}
+
+std::string ImageDescriptorCase::genResourceAccessSource (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+
+	const char* const	dimensionArray	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? ("1DArray")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? ("2DArray")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? ("3D")
+										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("CubeArray")
+										: (DE_NULL);
+	const char* const	accessPostfixA	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? ("")
+										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? ("A")
+										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? ("[0]")
+										: (DE_NULL);
+	const char* const	accessPostfixB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? ("")
+										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? ("B")
+										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? ("[1]")
+										: (DE_NULL);
+
+	switch (m_descriptorType)
+	{
+		case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+		case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+		{
+			const std::string	coodStr[4]	=
+			{
+				genSampleCoordStr(0),
+				genSampleCoordStr(1),
+				genSampleCoordStr(2),
+				genSampleCoordStr(3),
+			};
+			std::ostringstream	buf;
+
+			if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
+			{
+				buf << "	if (quadrant_id == 0)\n"
+					<< "		result_color = textureLod(sampler" << dimensionArray << "(u_separateTexture, u_separateSampler" << accessPostfixA << "), " << coodStr[0] << ", 0.0);\n"
+					<< "	else if (quadrant_id == 1)\n"
+					<< "		result_color = textureLod(sampler" << dimensionArray << "(u_separateTexture, u_separateSampler" << accessPostfixB << "), " << coodStr[1] << ", 0.0);\n"
+					<< "	else if (quadrant_id == 2)\n"
+					<< "		result_color = textureLod(sampler" << dimensionArray << "(u_separateTexture, u_separateSampler" << accessPostfixA << "), " << coodStr[2] << ", 0.0);\n"
+					<< "	else\n"
+					<< "		result_color = textureLod(sampler" << dimensionArray << "(u_separateTexture, u_separateSampler" << accessPostfixB << "), " << coodStr[3] << ", 0.0);\n";
+			}
+			else
+			{
+				buf << "	if (quadrant_id == 0)\n"
+					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixA << ", " << coodStr[0] << ", 0.0);\n"
+					<< "	else if (quadrant_id == 1)\n"
+					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixB << ", " << coodStr[1] << ", 0.0);\n"
+					<< "	else if (quadrant_id == 2)\n"
+					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixA << ", " << coodStr[2] << ", 0.0);\n"
+					<< "	else\n"
+					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixB << ", " << coodStr[3] << ", 0.0);\n";
+			}
+
+			return buf.str();
+		}
+
+		case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+		case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+		{
+			const std::string	coodStr[4]	=
+			{
+				genFetchCoordStr(0),
+				genFetchCoordStr(1),
+				genFetchCoordStr(2),
+				genFetchCoordStr(3),
+			};
+			std::ostringstream	buf;
+
+			if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
+			{
+				buf << "	if (quadrant_id == 0)\n"
+					<< "		result_color = textureFetch(u_separateTexture" << accessPostfixA << ", " << coodStr[0] << ", 0);\n"
+					<< "	else if (quadrant_id == 1)\n"
+					<< "		result_color = textureFetch(u_separateTexture" << accessPostfixB << ", " << coodStr[1] << ", 0);\n"
+					<< "	else if (quadrant_id == 2)\n"
+					<< "		result_color = textureFetch(u_separateTexture" << accessPostfixA << ", " << coodStr[2] << ", 0);\n"
+					<< "	else\n"
+					<< "		result_color = textureFetch(u_separateTexture" << accessPostfixB << ", " << coodStr[3] << ", 0);\n";
+			}
+			else
+			{
+				buf << "	if (quadrant_id == 0)\n"
+					<< "		result_color = imageLoad(u_image" << accessPostfixA << ", " << coodStr[0] << ");\n"
+					<< "	else if (quadrant_id == 1)\n"
+					<< "		result_color = imageLoad(u_image" << accessPostfixB << ", " << coodStr[1] << ");\n"
+					<< "	else if (quadrant_id == 2)\n"
+					<< "		result_color = imageLoad(u_image" << accessPostfixA << ", " << coodStr[2] << ");\n"
+					<< "	else\n"
+					<< "		result_color = imageLoad(u_image" << accessPostfixB << ", " << coodStr[3] << ");\n";
+			}
+
+			return buf.str();
+		}
+
+		default:
+			DE_FATAL("invalid descriptor");
+			return "";
+	}
+}
+
+std::string ImageDescriptorCase::genNoAccessSource (void) const
+{
+	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+			"		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+			"	else\n"
+			"		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
+}
+
+vkt::TestInstance* ImageDescriptorCase::createInstance (vkt::Context& context) const
+{
+	switch (m_descriptorType)
+	{
+		case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+		case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+			if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
+			{
+				DE_ASSERT(m_isPrimaryCmdBuf);
+				return new ImageSampleComputeInstance(context, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
+			}
+			else
+				return new ImageSampleRenderInstance(context, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
+
+		case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+		case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+			if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
+			{
+				DE_ASSERT(m_isPrimaryCmdBuf);
+				return new ImageFetchComputeInstance(context, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
+			}
+			else
+				return new ImageFetchRenderInstance(context, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
+
+		default:
+			DE_FATAL("Impossible");
+			return DE_NULL;
+	}
+}
+
+class TexelBufferInstanceBuffers
+{
+public:
+										TexelBufferInstanceBuffers	(const vk::DeviceInterface&		vki,
+																	 vk::VkDevice					device,
+																	 vk::Allocator&					allocator,
+																	 vk::VkDescriptorType			descriptorType,
+																	 int							numTexelBuffers,
+																	 bool							hasViewOffset);
+
+private:
+	static vk::Move<vk::VkBuffer>		createBuffer				(const vk::DeviceInterface&		vki,
+																	 vk::VkDevice					device,
+																	 vk::Allocator&					allocator,
+																	 vk::VkDescriptorType			descriptorType,
+																	 de::MovePtr<vk::Allocation>	*outAllocation);
+
+	static vk::Move<vk::VkBufferView>	createBufferView			(const vk::DeviceInterface&		vki,
+																	 vk::VkDevice					device,
+																	 const tcu::TextureFormat&		textureFormat,
+																	 deUint32						offset,
+																	 vk::VkBuffer					buffer);
+
+	static vk::VkBufferMemoryBarrier	createBarrier				(vk::VkDescriptorType descriptorType, vk::VkBuffer buffer);
+
+	void								populateSourceBuffer		(const tcu::PixelBufferAccess& access);
+	void								uploadData					(const vk::DeviceInterface& vki, vk::VkDevice device, const vk::Allocation& memory, const de::ArrayBuffer<deUint8>& data);
+
+public:
+	static int							getFetchPos					(int fetchPosNdx);
+	tcu::Vec4							fetchTexelValue				(int fetchPosNdx) const;
+
+	inline int							getNumTexelBuffers			(void) const { return m_numTexelBuffers;	}
+	const tcu::TextureFormat&			getTextureFormat			(void) const { return m_imageFormat;		}
+	inline vk::VkBufferView				getBufferViewA				(void) const { return *m_bufferViewA;		}
+	inline vk::VkBufferView				getBufferViewB				(void) const { return *m_bufferViewB;		}
+	inline const void*					getBufferInitBarrierA		(void) const { return &m_bufferBarrierA;	}
+	inline const void*					getBufferInitBarrierB		(void) const { return &m_bufferBarrierB;	}
+
+private:
+	enum
+	{
+		BUFFER_SIZE			= 512,
+		VIEW_OFFSET_VALUE	= 256,
+		VIEW_DATA_SIZE		= 256,	//!< size in bytes
+		VIEW_WIDTH			= 64,	//!< size in pixels
+	};
+	enum
+	{
+		// some arbitrary points
+		SAMPLE_POINT_0 = 6,
+		SAMPLE_POINT_1 = 51,
+		SAMPLE_POINT_2 = 42,
+		SAMPLE_POINT_3 = 25,
+	};
+
+	const deUint32						m_numTexelBuffers;
+	const tcu::TextureFormat			m_imageFormat;
+	const deUint32						m_viewOffset;
+
+	de::ArrayBuffer<deUint8>			m_sourceBufferA;
+	de::ArrayBuffer<deUint8>			m_sourceBufferB;
+	const tcu::ConstPixelBufferAccess	m_sourceViewA;
+	const tcu::ConstPixelBufferAccess	m_sourceViewB;
+
+	de::MovePtr<vk::Allocation>			m_bufferMemoryA;
+	de::MovePtr<vk::Allocation>			m_bufferMemoryB;
+	const vk::Unique<vk::VkBuffer>		m_bufferA;
+	const vk::Unique<vk::VkBuffer>		m_bufferB;
+	const vk::Unique<vk::VkBufferView>	m_bufferViewA;
+	const vk::Unique<vk::VkBufferView>	m_bufferViewB;
+	const vk::VkBufferMemoryBarrier		m_bufferBarrierA;
+	const vk::VkBufferMemoryBarrier		m_bufferBarrierB;
+};
+
+TexelBufferInstanceBuffers::TexelBufferInstanceBuffers (const vk::DeviceInterface&		vki,
+														vk::VkDevice					device,
+														vk::Allocator&					allocator,
+														vk::VkDescriptorType			descriptorType,
+														int								numTexelBuffers,
+														bool							hasViewOffset)
+	: m_numTexelBuffers	(numTexelBuffers)
+	, m_imageFormat		(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
+	, m_viewOffset		((hasViewOffset) ? ((deUint32)VIEW_OFFSET_VALUE) : (0u))
+	, m_sourceBufferA	(BUFFER_SIZE)
+	, m_sourceBufferB	((numTexelBuffers == 1)
+							? (0u)
+							: ((size_t)BUFFER_SIZE))
+	, m_sourceViewA		(m_imageFormat, tcu::IVec3(VIEW_WIDTH, 1, 1), m_sourceBufferA.getElementPtr(m_viewOffset))
+	, m_sourceViewB		(m_imageFormat, tcu::IVec3(VIEW_WIDTH, 1, 1), m_sourceBufferB.getElementPtr(m_viewOffset))
+	, m_bufferMemoryA	(DE_NULL)
+	, m_bufferMemoryB	(DE_NULL)
+	, m_bufferA			(createBuffer(vki, device, allocator, descriptorType, &m_bufferMemoryA))
+	, m_bufferB			((numTexelBuffers == 1)
+							? vk::Move<vk::VkBuffer>()
+							: createBuffer(vki, device, allocator, descriptorType, &m_bufferMemoryB))
+	, m_bufferViewA		(createBufferView(vki, device, m_imageFormat, m_viewOffset, *m_bufferA))
+	, m_bufferViewB		((numTexelBuffers == 1)
+							? vk::Move<vk::VkBufferView>()
+							: createBufferView(vki, device, m_imageFormat, m_viewOffset, *m_bufferB))
+	, m_bufferBarrierA	(createBarrier(descriptorType, *m_bufferA))
+	, m_bufferBarrierB	(createBarrier(descriptorType, *m_bufferB))
+{
+	DE_ASSERT(numTexelBuffers == 1 || numTexelBuffers == 2);
+	DE_ASSERT(VIEW_WIDTH * m_imageFormat.getPixelSize() == VIEW_DATA_SIZE);
+	DE_ASSERT(BUFFER_SIZE % m_imageFormat.getPixelSize() == 0);
+
+	// specify and upload
+
+	populateSourceBuffer(tcu::PixelBufferAccess(m_imageFormat, tcu::IVec3(BUFFER_SIZE / m_imageFormat.getPixelSize(), 1, 1), m_sourceBufferA.getPtr()));
+	uploadData(vki, device, *m_bufferMemoryA, m_sourceBufferA);
+
+	if (numTexelBuffers == 2)
+	{
+		populateSourceBuffer(tcu::PixelBufferAccess(m_imageFormat, tcu::IVec3(BUFFER_SIZE / m_imageFormat.getPixelSize(), 1, 1), m_sourceBufferB.getPtr()));
+		uploadData(vki, device, *m_bufferMemoryB, m_sourceBufferB);
+	}
+}
+
+vk::Move<vk::VkBuffer> TexelBufferInstanceBuffers::createBuffer (const vk::DeviceInterface&		vki,
+																 vk::VkDevice					device,
+																 vk::Allocator&					allocator,
+																 vk::VkDescriptorType			descriptorType,
+																 de::MovePtr<vk::Allocation>	*outAllocation)
+{
+	const vk::VkBufferUsageFlags	usage		= (isUniformDescriptorType(descriptorType)) ? (vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
+	const vk::VkBufferCreateInfo	createInfo	=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		(vk::VkDeviceSize)BUFFER_SIZE,		// size
+		usage,								// usage
+		0u,									// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,		// sharingMode
+		0u,									// queueFamilyCount
+		DE_NULL,							// pQueueFamilyIndices
+	};
+	vk::Move<vk::VkBuffer>			buffer		(vk::createBuffer(vki, device, &createInfo));
+	de::MovePtr<vk::Allocation>		allocation	(allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
+
+	*outAllocation = allocation;
+	return buffer;
+}
+
+vk::Move<vk::VkBufferView> TexelBufferInstanceBuffers::createBufferView (const vk::DeviceInterface&		vki,
+																		 vk::VkDevice					device,
+																		 const tcu::TextureFormat&		textureFormat,
+																		 deUint32						offset,
+																		 vk::VkBuffer					buffer)
+{
+	const vk::VkBufferViewCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
+		DE_NULL,
+		buffer,									// buffer
+		mapToVkTextureFormat(textureFormat),	// format
+		(vk::VkDeviceSize)offset,				// offset
+		(vk::VkDeviceSize)VIEW_DATA_SIZE		// range
+	};
+	return vk::createBufferView(vki, device, &createInfo);
+}
+
+vk::VkBufferMemoryBarrier TexelBufferInstanceBuffers::createBarrier (vk::VkDescriptorType descriptorType, vk::VkBuffer buffer)
+{
+	const vk::VkMemoryInputFlags	inputBit	= (isUniformDescriptorType(descriptorType)) ? (vk::VK_MEMORY_INPUT_UNIFORM_READ_BIT) : (vk::VK_MEMORY_INPUT_SHADER_READ_BIT);
+	const vk::VkBufferMemoryBarrier	barrier		=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+		DE_NULL,
+		vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,	// outputMask
+		inputBit,								// inputMask
+		vk::VK_QUEUE_FAMILY_IGNORED,			// srcQueueFamilyIndex
+		vk::VK_QUEUE_FAMILY_IGNORED,			// destQueueFamilyIndex
+		buffer	,								// buffer
+		0u,										// offset
+		(vk::VkDeviceSize)BUFFER_SIZE			// size
+	};
+	return barrier;
+}
+
+void TexelBufferInstanceBuffers::populateSourceBuffer (const tcu::PixelBufferAccess& access)
+{
+	DE_ASSERT(access.getHeight() == 1);
+	DE_ASSERT(access.getDepth() == 1);
+
+	const deInt32 width = access.getWidth();
+
+	for (int x = 0; x < width; ++x)
+	{
+		const int			red		= 255 * x / width;												//!< gradient from 0 -> max (detects large offset errors)
+		const int			green	= ((x % 2 == 0) ? (127) : (0)) + ((x % 4 < 3) ? (128) : (0));	//!< 3-level M pattern (detects small offset errors)
+		const int			blue	= 16 * (x % 16);												//!< 16-long triangle wave
+
+		DE_ASSERT(de::inRange(red, 0, 255));
+		DE_ASSERT(de::inRange(green, 0, 255));
+		DE_ASSERT(de::inRange(blue, 0, 255));
+
+		access.setPixel(tcu::IVec4(red, green, blue, 255), x, 0, 0);
+	}
+}
+
+void TexelBufferInstanceBuffers::uploadData (const vk::DeviceInterface& vki, vk::VkDevice device, const vk::Allocation& memory, const de::ArrayBuffer<deUint8>& data)
+{
+	deMemcpy(memory.getHostPtr(), data.getPtr(), data.size());
+	flushMappedMemoryRange(vki, device, memory.getMemory(), memory.getOffset(), data.size());
+}
+
+int TexelBufferInstanceBuffers::getFetchPos (int fetchPosNdx)
+{
+	static const int fetchPositions[4] =
+	{
+		SAMPLE_POINT_0,
+		SAMPLE_POINT_1,
+		SAMPLE_POINT_2,
+		SAMPLE_POINT_3,
+	};
+	return de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
+}
+
+tcu::Vec4 TexelBufferInstanceBuffers::fetchTexelValue (int fetchPosNdx) const
+{
+	// source order is ABAB
+	const tcu::ConstPixelBufferAccess&	texelSrcA	= m_sourceViewA;
+	const tcu::ConstPixelBufferAccess&	texelSrcB	= (m_numTexelBuffers == 1) ? (m_sourceViewA) : (m_sourceViewB);
+	const tcu::ConstPixelBufferAccess&	texelSrc	= ((fetchPosNdx % 2) == 0) ? (texelSrcA) : (texelSrcB);
+
+	return texelSrc.getPixel(getFetchPos(fetchPosNdx), 0, 0);
+}
+
+class TexelBufferRenderInstance : public SingleCmdRenderInstance
+{
+public:
+													TexelBufferRenderInstance	(vkt::Context&			context,
+																				 bool					isPrimaryCmdBuf,
+																				 vk::VkDescriptorType	descriptorType,
+																				 vk::VkShaderStageFlags	stageFlags,
+																				 ShaderInputInterface	shaderInterface,
+																				 bool					nonzeroViewOffset);
+
+private:
+	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkShaderStageFlags		stageFlags);
+
+	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorSetLayout	descriptorSetLayout);
+
+	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface);
+
+	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(const vk::DeviceInterface&	vki,
+																				 vk::VkDevice				device,
+																				 vk::VkDescriptorType		descriptorType,
+																				 ShaderInputInterface		shaderInterface,
+																				 vk::VkDescriptorSetLayout	layout,
+																				 vk::VkDescriptorPool		pool,
+																				 vk::VkBufferView			viewA,
+																				 vk::VkBufferView			viewB);
+
+	void											logTestPlan					(void) const;
+	vk::VkPipelineLayout							getPipelineLayout			(void) const;
+	void											writeDrawCmdBuffer			(vk::VkCmdBuffer cmd) const;
+	tcu::TestStatus									verifyResultImage			(const tcu::ConstPixelBufferAccess& result) const;
+
+	enum
+	{
+		RENDER_SIZE = 128,
+	};
+
+	const vk::VkDescriptorType						m_descriptorType;
+	const vk::VkShaderStageFlags					m_stageFlags;
+	const ShaderInputInterface						m_shaderInterface;
+	const bool										m_nonzeroViewOffset;
+
+	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
+	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
+	const TexelBufferInstanceBuffers				m_texelBuffers;
+	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
+	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
+};
+
+TexelBufferRenderInstance::TexelBufferRenderInstance (vkt::Context&				context,
+													  bool						isPrimaryCmdBuf,
+													  vk::VkDescriptorType		descriptorType,
+													  vk::VkShaderStageFlags	stageFlags,
+													  ShaderInputInterface		shaderInterface,
+													  bool						nonzeroViewOffset)
+	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
+	, m_descriptorType			(descriptorType)
+	, m_stageFlags				(stageFlags)
+	, m_shaderInterface			(shaderInterface)
+	, m_nonzeroViewOffset		(nonzeroViewOffset)
+	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags))
+	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
+	, m_texelBuffers			(m_vki, m_device, m_allocator, m_descriptorType, getInterfaceNumResources(m_shaderInterface), m_nonzeroViewOffset)
+	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
+	, m_descriptorSet			(createDescriptorSet(m_vki, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, m_texelBuffers.getBufferViewA(), m_texelBuffers.getBufferViewB()))
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> TexelBufferRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&	vki,
+																						  vk::VkDevice					device,
+																						  vk::VkDescriptorType			descriptorType,
+																						  ShaderInputInterface			shaderInterface,
+																						  vk::VkShaderStageFlags		stageFlags)
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(descriptorType, stageFlags);
+			builder.addSingleBinding(descriptorType, stageFlags);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(descriptorType, 2u, stageFlags);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	return builder.build(vki, device);
+}
+
+vk::Move<vk::VkPipelineLayout> TexelBufferRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
+																				vk::VkDevice				device,
+																				vk::VkDescriptorSetLayout	descriptorSetLayout)
+{
+	const vk::VkPipelineLayoutCreateInfo createInfo =
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+		DE_NULL,
+		1,						// descriptorSetCount
+		&descriptorSetLayout,	// pSetLayouts
+		0u,						// pushConstantRangeCount
+		DE_NULL,				// pPushConstantRanges
+	};
+	return vk::createPipelineLayout(vki, device, &createInfo);
+}
+
+vk::Move<vk::VkDescriptorPool> TexelBufferRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
+																				vk::VkDevice					device,
+																				vk::VkDescriptorType			descriptorType,
+																				ShaderInputInterface			shaderInterface)
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
+		.build(vki, device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> TexelBufferRenderInstance::createDescriptorSet (const vk::DeviceInterface&	vki,
+																			  vk::VkDevice					device,
+																			  vk::VkDescriptorType			descriptorType,
+																			  ShaderInputInterface			shaderInterface,
+																			  vk::VkDescriptorSetLayout		layout,
+																			  vk::VkDescriptorPool			pool,
+																			  vk::VkBufferView				viewA,
+																			  vk::VkBufferView				viewB)
+{
+	const vk::VkDescriptorInfo		texelBufferInfos[2]	=
+	{
+		createDescriptorInfo(viewA),
+		createDescriptorInfo(viewB),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet		= allocDescriptorSet(vki, device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	switch (shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &texelBufferInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, texelBufferInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(vki, device);
+	return descriptorSet;
+}
+
+void TexelBufferRenderInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Rendering 2x2 grid.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
+		<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
+		<< "Buffer format is " << vk::getFormatName(mapToVkTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
+
+	if (m_stageFlags == 0u)
+	{
+		msg << "Descriptors are not accessed in any shader stage.\n";
+	}
+	else
+	{
+		msg << "Color in each cell is fetched using the descriptor(s):\n";
+
+		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+		{
+			msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
+
+			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+			{
+				const int srcResourceNdx = (resultNdx % 2); // ABAB source
+				msg << " from texelBuffer " << srcResourceNdx;
+			}
+
+			msg << "\n";
+		}
+
+		msg << "Descriptors are accessed in {"
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)			? (" vertex")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)		? (" geometry")			: (""))
+			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)		? (" fragment")			: (""))
+			<< " } stages.";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+vk::VkPipelineLayout TexelBufferRenderInstance::getPipelineLayout (void) const
+{
+	return *m_pipelineLayout;
+}
+
+void TexelBufferRenderInstance::writeDrawCmdBuffer (vk::VkCmdBuffer cmd) const
+{
+	m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
+	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
+}
+
+tcu::TestStatus TexelBufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
+{
+	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
+	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
+	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
+	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_texelBuffers.fetchTexelValue(0));
+	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_texelBuffers.fetchTexelValue(1));
+	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_texelBuffers.fetchTexelValue(2));
+	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_texelBuffers.fetchTexelValue(3));
+	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
+
+	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
+
+	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
+		return tcu::TestStatus::fail("Image verification failed");
+	else
+		return tcu::TestStatus::pass("Pass");
+}
+
+class TexelBufferComputeInstance : public vkt::TestInstance
+{
+public:
+											TexelBufferComputeInstance	(vkt::Context&			context,
+																		 vk::VkDescriptorType	descriptorType,
+																		 ShaderInputInterface	shaderInterface,
+																		 bool					nonzeroViewOffset);
+
+private:
+	vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout	(void) const;
+	vk::Move<vk::VkDescriptorPool>			createDescriptorPool		(void) const;
+	vk::Move<vk::VkDescriptorSet>			createDescriptorSet			(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const;
+
+	tcu::TestStatus							iterate						(void);
+	void									logTestPlan					(void) const;
+	tcu::TestStatus							testResourceAccess			(void);
+
+	const vk::VkDescriptorType				m_descriptorType;
+	const ShaderInputInterface				m_shaderInterface;
+	const bool								m_nonzeroViewOffset;
+
+	const vk::DeviceInterface&				m_vki;
+	const vk::VkDevice						m_device;
+	const vk::VkQueue						m_queue;
+	const deUint32							m_queueFamilyIndex;
+	vk::Allocator&							m_allocator;
+
+	const ComputeInstanceResultBuffer		m_result;
+	const TexelBufferInstanceBuffers		m_texelBuffers;
+};
+
+TexelBufferComputeInstance::TexelBufferComputeInstance (Context&				context,
+														vk::VkDescriptorType	descriptorType,
+														ShaderInputInterface	shaderInterface,
+														bool					nonzeroViewOffset)
+	: vkt::TestInstance		(context)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_nonzeroViewOffset	(nonzeroViewOffset)
+	, m_vki					(context.getDeviceInterface())
+	, m_device				(context.getDevice())
+	, m_queue				(context.getUniversalQueue())
+	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
+	, m_allocator			(context.getDefaultAllocator())
+	, m_result				(m_vki, m_device, m_allocator)
+	, m_texelBuffers		(m_vki, m_device, m_allocator, m_descriptorType, getInterfaceNumResources(m_shaderInterface), m_nonzeroViewOffset)
+{
+}
+
+vk::Move<vk::VkDescriptorSetLayout> TexelBufferComputeInstance::createDescriptorSetLayout (void) const
+{
+	vk::DescriptorSetLayoutBuilder builder;
+
+	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	};
+
+	return builder.build(m_vki, m_device);
+}
+
+vk::Move<vk::VkDescriptorPool> TexelBufferComputeInstance::createDescriptorPool (void) const
+{
+	return vk::DescriptorPoolBuilder()
+		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
+		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1);
+}
+
+vk::Move<vk::VkDescriptorSet> TexelBufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout) const
+{
+	const vk::VkDescriptorInfo		resultInfo			= createDescriptorInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
+	const vk::VkDescriptorInfo		texelBufferInfos[2]	=
+	{
+		createDescriptorInfo(m_texelBuffers.getBufferViewA()),
+		createDescriptorInfo(m_texelBuffers.getBufferViewB()),
+	};
+
+	vk::Move<vk::VkDescriptorSet>	descriptorSet		= allocDescriptorSet(m_vki, m_device, pool, vk::VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	vk::DescriptorSetUpdateBuilder	builder;
+
+	// result
+	builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
+
+	// texel buffers
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &texelBufferInfos[0]);
+			break;
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &texelBufferInfos[0]);
+			builder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &texelBufferInfos[1]);
+			break;
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			builder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, texelBufferInfos);
+			break;
+
+		default:
+			DE_FATAL("Impossible");
+	}
+
+	builder.update(m_vki, m_device);
+	return descriptorSet;
+}
+
+tcu::TestStatus TexelBufferComputeInstance::iterate (void)
+{
+	logTestPlan();
+	return testResourceAccess();
+}
+
+void TexelBufferComputeInstance::logTestPlan (void) const
+{
+	std::ostringstream msg;
+
+	msg << "Fetching 4 values from image in compute shader.\n"
+		<< "Single descriptor set. Descriptor set contains "
+			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
+			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS) ? "two" :
+			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
+			    (const char*)DE_NULL)
+		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
+		<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
+		<< "Buffer format is " << vk::getFormatName(mapToVkTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
+
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
+
+		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
+		{
+			const int srcResourceNdx = (resultNdx % 2); // ABAB source
+			msg << " from texelBuffer " << srcResourceNdx;
+		}
+
+		msg << "\n";
+	}
+
+	m_context.getTestContext().getLog()
+		<< tcu::TestLog::Message
+		<< msg.str()
+		<< tcu::TestLog::EndMessage;
+}
+
+tcu::TestStatus TexelBufferComputeInstance::testResourceAccess (void)
+{
+	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
+	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
+	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
+	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
+
+	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
+	const int										numDescriptorSets	= DE_LENGTH_OF_ARRAY(descriptorSets);
+	const deUint32* const							dynamicOffsets		= DE_NULL;
+	const int										numDynamicOffsets	= 0;
+	const void*	const								preBarriers[]		= { m_texelBuffers.getBufferInitBarrierA(), m_texelBuffers.getBufferInitBarrierB() };
+	const int										numPreBarriers		= m_texelBuffers.getNumTexelBuffers();
+	const void* const								postBarriers[]		= { m_result.getResultReadBarrier() };
+	const int										numPostBarriers		= DE_LENGTH_OF_ARRAY(postBarriers);
+
+	const ComputeCommand							compute				(m_vki,
+																		 m_device,
+																		 pipeline.getPipeline(),
+																		 pipeline.getPipelineLayout(),
+																		 tcu::UVec3(4, 1, 1),
+																		 numDescriptorSets,	descriptorSets,
+																		 numDynamicOffsets,	dynamicOffsets,
+																		 numPreBarriers,	preBarriers,
+																		 numPostBarriers,	postBarriers);
+
+	tcu::Vec4										results[4];
+	bool											anyResultSet		= false;
+	bool											allResultsOk		= true;
+
+	compute.submitAndWait(m_queueFamilyIndex, m_queue);
+	m_result.readResultContentsTo(&results);
+
+	// verify
+	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
+	{
+		const tcu::Vec4	result				= results[resultNdx];
+		const tcu::Vec4	reference			= m_texelBuffers.fetchTexelValue(resultNdx);
+		const tcu::Vec4	conversionThreshold	= tcu::Vec4(1.0f / 255.0f);
+
+		if (result != tcu::Vec4(-1.0f))
+			anyResultSet = true;
+
+		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
+		{
+			allResultsOk = false;
+
+			m_context.getTestContext().getLog()
+				<< tcu::TestLog::Message
+				<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
+				<< tcu::TestLog::EndMessage;
+		}
+	}
+
+	// read back and verify
+	if (allResultsOk)
+		return tcu::TestStatus::pass("Pass");
+	else if (anyResultSet)
+		return tcu::TestStatus::fail("Invalid result values");
+	else
+	{
+		m_context.getTestContext().getLog()
+			<< tcu::TestLog::Message
+			<< "Result buffer was not written to."
+			<< tcu::TestLog::EndMessage;
+		return tcu::TestStatus::fail("Result buffer was not written to");
+	}
+}
+
+class TexelBufferDescriptorCase : public QuadrantRendederCase
+{
+public:
+	enum
+	{
+		FLAG_VIEW_OFFSET = (1u << 1u),
+	};
+	// enum continues where resource flags ends
+	DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
+
+								TexelBufferDescriptorCase	(tcu::TestContext&		testCtx,
+															 const char*			name,
+															 const char*			description,
+															 bool					isPrimaryCmdBuf,
+															 vk::VkDescriptorType	descriptorType,
+															 vk::VkShaderStageFlags	exitingStages,
+															 vk::VkShaderStageFlags	activeStages,
+															 ShaderInputInterface	shaderInterface,
+															 deUint32				flags);
+
+private:
+	std::string					genExtensionDeclarations	(vk::VkShaderStage stage) const;
+	std::string					genResourceDeclarations		(vk::VkShaderStage stage, int numUsedBindings) const;
+	std::string					genResourceAccessSource		(vk::VkShaderStage stage) const;
+	std::string					genNoAccessSource			(void) const;
+
+	vkt::TestInstance*			createInstance				(vkt::Context& context) const;
+
+	const bool					m_isPrimaryCmdBuf;
+	const vk::VkDescriptorType	m_descriptorType;
+	const ShaderInputInterface	m_shaderInterface;
+	const bool					m_nonzeroViewOffset;
+};
+
+TexelBufferDescriptorCase::TexelBufferDescriptorCase (tcu::TestContext&			testCtx,
+													  const char*				name,
+													  const char*				description,
+													  bool						isPrimaryCmdBuf,
+													  vk::VkDescriptorType		descriptorType,
+													  vk::VkShaderStageFlags	exitingStages,
+													  vk::VkShaderStageFlags	activeStages,
+													  ShaderInputInterface		shaderInterface,
+													  deUint32					flags)
+	: QuadrantRendederCase	(testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages)
+	, m_isPrimaryCmdBuf		(isPrimaryCmdBuf)
+	, m_descriptorType		(descriptorType)
+	, m_shaderInterface		(shaderInterface)
+	, m_nonzeroViewOffset	(((flags & FLAG_VIEW_OFFSET) != 0) ? (1u) : (0u))
+{
+}
+
+std::string TexelBufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+	return "#extension GL_EXT_texture_buffer : require\n";
+}
+
+std::string TexelBufferDescriptorCase::genResourceDeclarations (vk::VkShaderStage stage, int numUsedBindings) const
+{
+	DE_UNREF(stage);
+
+	const bool			isUniform		= isUniformDescriptorType(m_descriptorType);
+	const char* const	storageType		= (isUniform) ? ("samplerBuffer ") : ("readonly imageBuffer ");
+	const char* const	formatQualifier	= (isUniform) ? ("") : (", rgba8");
+
+	switch (m_shaderInterface)
+	{
+		case SHADER_INPUT_SINGLE_DESCRIPTOR:
+			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBuffer;\n";
+
+		case SHADER_INPUT_MULTIPLE_DESCRIPTORS:
+			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBufferA;\n"
+				   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + formatQualifier + ") uniform highp " + storageType + " u_texelBufferB;\n";
+
+		case SHADER_INPUT_DESCRIPTOR_ARRAY:
+			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBuffer[2];\n";
+
+		default:
+			DE_FATAL("Impossible");
+			return "";
+	}
+}
+
+std::string TexelBufferDescriptorCase::genResourceAccessSource (vk::VkShaderStage stage) const
+{
+	DE_UNREF(stage);
+
+	const char* const	accessPostfixA	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? ("")
+										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? ("A")
+										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? ("[0]")
+										: (DE_NULL);
+	const char* const	accessPostfixB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)		? ("")
+										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DESCRIPTORS)	? ("B")
+										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)		? ("[1]")
+										: (DE_NULL);
+	const char* const	fetchFunc		= (isUniformDescriptorType(m_descriptorType)) ? ("texelFetch") : ("imageLoad");
+	std::ostringstream	buf;
+
+	buf << "	if (quadrant_id == 0)\n"
+		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(0) << ");\n"
+		<< "	else if (quadrant_id == 1)\n"
+		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(1) << ");\n"
+		<< "	else if (quadrant_id == 2)\n"
+		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(2) << ");\n"
+		<< "	else\n"
+		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(3) << ");\n";
+
+	return buf.str();
+}
+
+std::string TexelBufferDescriptorCase::genNoAccessSource (void) const
+{
+	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
+			"		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+			"	else\n"
+			"		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
+}
+
+vkt::TestInstance* TexelBufferDescriptorCase::createInstance (vkt::Context& context) const
+{
+	if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
+	{
+		DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
+		return new TexelBufferComputeInstance(context, m_descriptorType, m_shaderInterface, m_nonzeroViewOffset);
+	}
+	else
+		return new TexelBufferRenderInstance(context, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_nonzeroViewOffset);
+}
+
+void createShaderAccessImageTests (tcu::TestCaseGroup*		group,
+								   bool						isPrimaryCmdBuf,
+								   vk::VkDescriptorType		descriptorType,
+								   vk::VkShaderStageFlags	exitingStages,
+								   vk::VkShaderStageFlags	activeStages,
+								   ShaderInputInterface		dimension,
+								   deUint32					resourceFlags)
+{
+	static const struct
+	{
+		vk::VkImageViewType	viewType;
+		const char*			name;
+		const char*			description;
+		deUint32			flags;
+	} s_imageTypes[] =
+	{
+		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d",						"1D image view",								0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d_base_mip",				"1D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d_base_slice",			"1D image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
+
+		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array",					"1D array image view",							0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array_base_mip",		"1D array image subview with base mip level",	ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array_base_slice",		"1D array image subview with base array slice",	ImageDescriptorCase::FLAG_BASE_SLICE	},
+
+		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d",						"2D image view",								0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d_base_mip",				"2D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d_base_slice",			"2D image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
+
+		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array",					"2D array image view",							0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array_base_mip",		"2D array image subview with base mip level",	ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array_base_slice",		"2D array image subview with base array slice",	ImageDescriptorCase::FLAG_BASE_SLICE	},
+
+		{ vk::VK_IMAGE_VIEW_TYPE_3D,			"3d",						"3D image view",								0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_3D,			"3d_base_mip",				"3D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
+		// no 3d array textures
+
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube",						"Cube image view",								0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube_base_mip",			"Cube image subview with base mip level",		ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube_base_slice",			"Cube image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
+
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array",				"Cube image view",								0u										},
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array_base_mip",		"Cube image subview with base mip level",		ImageDescriptorCase::FLAG_BASE_MIP		},
+		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array_base_slice",	"Cube image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
+	};
+
+	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++ndx)
+	{
+		// never overlap
+		DE_ASSERT((s_imageTypes[ndx].flags & resourceFlags) == 0u);
+
+		group->addChild(new ImageDescriptorCase(group->getTestContext(),
+												s_imageTypes[ndx].name,
+												s_imageTypes[ndx].description,
+												isPrimaryCmdBuf,
+												descriptorType,
+												exitingStages,
+												activeStages,
+												dimension,
+												s_imageTypes[ndx].viewType,
+												s_imageTypes[ndx].flags | resourceFlags));
+	}
+}
+
+void createShaderAccessTexelBufferTests (tcu::TestCaseGroup*	group,
+										 bool					isPrimaryCmdBuf,
+										 vk::VkDescriptorType	descriptorType,
+										 vk::VkShaderStageFlags	exitingStages,
+										 vk::VkShaderStageFlags	activeStages,
+										 ShaderInputInterface	dimension,
+										 deUint32				resourceFlags)
+{
+	DE_ASSERT(resourceFlags == 0);
+	DE_UNREF(resourceFlags);
+
+	static const struct
+	{
+		const char*	name;
+		const char*	description;
+		deUint32	flags;
+	} s_texelBufferTypes[] =
+	{
+		{ "offset_zero",		"View offset is zero",		0u											},
+		{ "offset_nonzero",		"View offset is non-zero",	TexelBufferDescriptorCase::FLAG_VIEW_OFFSET	},
+	};
+
+	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_texelBufferTypes); ++ndx)
+	{
+		group->addChild(new TexelBufferDescriptorCase(group->getTestContext(),
+													  s_texelBufferTypes[ndx].name,
+													  s_texelBufferTypes[ndx].description,
+													  isPrimaryCmdBuf,
+													  descriptorType,
+													  exitingStages,
+													  activeStages,
+													  dimension,
+													  s_texelBufferTypes[ndx].flags));
+	}
+}
+
+void createShaderAccessBufferTests (tcu::TestCaseGroup*		group,
+									bool					isPrimaryCmdBuf,
+									vk::VkDescriptorType	descriptorType,
+									vk::VkShaderStageFlags	exitingStages,
+									vk::VkShaderStageFlags	activeStages,
+									ShaderInputInterface	dimension,
+									deUint32				resourceFlags)
+{
+	DE_ASSERT(resourceFlags == 0u);
+	DE_UNREF(resourceFlags);
+
+	static const struct
+	{
+		const char*	name;
+		const char*	description;
+		bool		isForDynamicCases;
+		deUint32	flags;
+	} s_bufferTypes[] =
+	{
+		{ "offset_view_zero",						"View offset is zero",										false,	0u																							},
+		{ "offset_view_nonzero",					"View offset is non-zero",									false,	BufferDescriptorCase::FLAG_VIEW_OFFSET														},
+
+		{ "offset_view_zero_dynamic_zero",			"View offset is zero, dynamic offset is zero",				true,	BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_ZERO												},
+		{ "offset_view_zero_dynamic_nonzero",		"View offset is zero, dynamic offset is non-zero",			true,	BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO											},
+		{ "offset_view_zero_dynamic_not_set",		"View offset is zero, dynamic offset is not supplied",		true,	0u																							},
+		// \note no case for offset_view_nonzero_dynamic_zero since it doesn't produce any additional coverage
+		{ "offset_view_nonzero_dynamic_nonzero",	"View offset is non-zero, dynamic offset is non-zero",		true,	BufferDescriptorCase::FLAG_VIEW_OFFSET | BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO	},
+		{ "offset_view_nonzero_dynamic_not_set",	"View offset is non-zero, dynamic offset is not supplied",	true,	BufferDescriptorCase::FLAG_VIEW_OFFSET														},
+	};
+
+	const bool isDynamicCase = isDynamicDescriptorType(descriptorType);
+
+	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_bufferTypes); ++ndx)
+	{
+		if (isDynamicCase == s_bufferTypes[ndx].isForDynamicCases)
+			group->addChild(new BufferDescriptorCase(group->getTestContext(),
+													 s_bufferTypes[ndx].name,
+													 s_bufferTypes[ndx].description,
+													 isPrimaryCmdBuf,
+													 descriptorType,
+													 exitingStages,
+													 activeStages,
+													 dimension,
+													 s_bufferTypes[ndx].flags));
+	}
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createShaderAccessTests (tcu::TestContext& testCtx)
+{
+	static const struct
+	{
+		const bool	isPrimary;
+		const char*	name;
+		const char*	description;
+	} s_bindTypes[] =
+	{
+		{ true,		"primary_cmd_buf",	"Bind in primary command buffer"	},
+		{ false,	"seconday_cmd_buf",	"Bind in secondary command buffer"	},
+	};
+	static const struct
+	{
+		const vk::VkDescriptorType	descriptorType;
+		const char*					name;
+		const char*					description;
+		deUint32					flags;
+	} s_descriptorTypes[] =
+	{
+		{ vk::VK_DESCRIPTOR_TYPE_SAMPLER,					"sampler_mutable",					"VK_DESCRIPTOR_TYPE_SAMPLER with mutable sampler",					0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_SAMPLER,					"sampler_immutable",				"VK_DESCRIPTOR_TYPE_SAMPLER with immutable sampler",				RESOURCE_FLAG_IMMUTABLE_SAMPLER	},
+		{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	"combined_image_sampler_mutable",	"VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with mutable sampler",	0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	"combined_image_sampler_immutable",	"VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with immutable sampler",	RESOURCE_FLAG_IMMUTABLE_SAMPLER	},
+		{ vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,				"sampled_image",					"VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE",									0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,				"storage_image",					"VK_DESCRIPTOR_TYPE_STORAGE_IMAGE",									0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,		"uniform_texel_buffer",				"VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER",							0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,		"storage_texel_buffer",				"VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER",							0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,			"uniform_buffer",					"VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER",								0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			"storage_buffer",					"VK_DESCRIPTOR_TYPE_STORAGE_BUFFER",								0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,	"uniform_buffer_dynamic",			"VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC",						0u								},
+		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,	"storage_buffer_dynamic",			"VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC",						0u								},
+	};
+	static const struct
+	{
+		const char*				name;
+		const char*				description;
+		vk::VkShaderStageFlags	existingStages;				//!< stages that exists
+		vk::VkShaderStageFlags	activeStages;				//!< stages that access resource
+		bool					supportsSecondaryCmdBufs;
+	} s_shaderStages[] =
+	{
+		{
+			"no_access",
+			"No accessing stages",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			0u,
+			true,
+		},
+		{
+			"vertex",
+			"Vertex stage",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_VERTEX_BIT,
+			true,
+		},
+		{
+			"tess_ctrl",
+			"Tessellation control stage",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESS_CONTROL_BIT | vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_TESS_CONTROL_BIT,
+			true,
+		},
+		{
+			"tess_eval",
+			"Tessellation evaluation stage",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESS_CONTROL_BIT | vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_TESS_EVALUATION_BIT,
+			true,
+		},
+		{
+			"geometry",
+			"Geometry stage",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_GEOMETRY_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_GEOMETRY_BIT,
+			true,
+		},
+		{
+			"fragment",
+			"Fragment stage",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			true,
+		},
+		{
+			"compute",
+			"Compute stage",
+			vk::VK_SHADER_STAGE_COMPUTE_BIT,
+			vk::VK_SHADER_STAGE_COMPUTE_BIT,
+			false,
+		},
+		{
+			"vertex_fragment",
+			"Vertex and fragment stages",
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
+			true,
+		},
+	};
+	static const struct
+	{
+		ShaderInputInterface	dimension;
+		const char*				name;
+		const char*				description;
+	} s_variableDimensions[] =
+	{
+		{ SHADER_INPUT_SINGLE_DESCRIPTOR,		"single_descriptor",	"Single descriptor"		},
+		{ SHADER_INPUT_MULTIPLE_DESCRIPTORS,	"multiple_descriptors",	"Multiple descriptors"	},
+		{ SHADER_INPUT_DESCRIPTOR_ARRAY,		"descriptor_array",		"Descriptor array"		},
+	};
+
+	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_access", "Access resource via descriptor in a single descriptor set"));
+
+	// .primary_cmd_buf...
+	for (int bindTypeNdx = 0; bindTypeNdx < DE_LENGTH_OF_ARRAY(s_bindTypes); ++bindTypeNdx)
+	{
+		de::MovePtr<tcu::TestCaseGroup> bindGroup(new tcu::TestCaseGroup(testCtx, s_bindTypes[bindTypeNdx].name, s_bindTypes[bindTypeNdx].description));
+
+		// .sampler, .combined_image_sampler, other resource types ...
+		for (int descriptorNdx = 0; descriptorNdx < DE_LENGTH_OF_ARRAY(s_descriptorTypes); ++descriptorNdx)
+		{
+			de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, s_descriptorTypes[descriptorNdx].name, s_descriptorTypes[descriptorNdx].description));
+
+			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(s_shaderStages); ++stageNdx)
+			{
+				if (s_bindTypes[bindTypeNdx].isPrimary || s_shaderStages[stageNdx].supportsSecondaryCmdBufs)
+				{
+					de::MovePtr<tcu::TestCaseGroup> stageGroup(new tcu::TestCaseGroup(testCtx, s_shaderStages[stageNdx].name, s_shaderStages[stageNdx].description));
+
+					for (int dimensionNdx = 0; dimensionNdx < DE_LENGTH_OF_ARRAY(s_variableDimensions); ++dimensionNdx)
+					{
+						de::MovePtr<tcu::TestCaseGroup>	dimensionGroup(new tcu::TestCaseGroup(testCtx, s_variableDimensions[dimensionNdx].name, s_variableDimensions[dimensionNdx].description));
+						void							(*createTestsFunc)(tcu::TestCaseGroup*		group,
+																		   bool						isPrimaryCmdBuf,
+																		   vk::VkDescriptorType		descriptorType,
+																		   vk::VkShaderStageFlags	existingStages,
+																		   vk::VkShaderStageFlags	activeStages,
+																		   ShaderInputInterface		dimension,
+																		   deUint32					resourceFlags);
+
+						switch (s_descriptorTypes[descriptorNdx].descriptorType)
+						{
+							case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
+							case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+							case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+							case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+								createTestsFunc = createShaderAccessImageTests;
+								break;
+
+							case vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+							case vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+								createTestsFunc = createShaderAccessTexelBufferTests;
+								break;
+
+							case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+							case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+							case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+							case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+								createTestsFunc = createShaderAccessBufferTests;
+								break;
+
+							default:
+								createTestsFunc = DE_NULL;
+								DE_FATAL("Impossible");
+						}
+
+						if (createTestsFunc)
+						{
+							createTestsFunc(dimensionGroup.get(),
+											s_bindTypes[bindTypeNdx].isPrimary,
+											s_descriptorTypes[descriptorNdx].descriptorType,
+											s_shaderStages[stageNdx].existingStages,
+											s_shaderStages[stageNdx].activeStages,
+											s_variableDimensions[dimensionNdx].dimension,
+											s_descriptorTypes[descriptorNdx].flags);
+						}
+						else
+							DE_FATAL("Impossible");
+
+						stageGroup->addChild(dimensionGroup.release());
+					}
+
+					typeGroup->addChild(stageGroup.release());
+				}
+			}
+
+			bindGroup->addChild(typeGroup.release());
+		}
+
+		group->addChild(bindGroup.release());
+	}
+
+	return group.release();
+}
+
+} // BindingModel
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.hpp b/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.hpp
new file mode 100644
index 0000000..7ff1b1a
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/binding_model/vktBindingShaderAccessTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTBINDINGSHADERACCESSTESTS_HPP
+#define _VKTBINDINGSHADERACCESSTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Binding shader access tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace BindingModel
+{
+
+tcu::TestCaseGroup* createShaderAccessTests (tcu::TestContext& testCtx);
+
+} // BindingModel
+} // vkt
+
+#endif // _VKTBINDINGSHADERACCESSTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt
new file mode 100644
index 0000000..601af66
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt
@@ -0,0 +1,33 @@
+
+include_directories(
+	..
+	)
+
+set(DEQP_VK_PIPELINE_SRCS
+	vktPipelineBlendTests.cpp
+	vktPipelineBlendTests.hpp
+	vktPipelineClearUtil.cpp
+	vktPipelineClearUtil.hpp
+	vktPipelineDepthTests.cpp
+	vktPipelineDepthTests.hpp
+	vktPipelineImageUtil.cpp
+	vktPipelineImageUtil.hpp
+	vktPipelineReferenceRenderer.cpp
+	vktPipelineReferenceRenderer.hpp
+	vktPipelineStencilTests.cpp
+	vktPipelineStencilTests.hpp
+	vktPipelineTests.cpp
+	vktPipelineTests.hpp
+	vktPipelineVertexUtil.cpp
+	vktPipelineVertexUtil.hpp
+	)
+
+set(DEQP_VK_PIPELINE_LIBS
+	tcutil
+	vkutil
+	referencerenderer
+	)
+
+add_library(deqp-vk-pipeline STATIC ${DEQP_VK_PIPELINE_SRCS})
+target_link_libraries(deqp-vk-pipeline ${DEQP_VK_PIPELINE_LIBS})
+
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.cpp
new file mode 100644
index 0000000..d9d029f
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.cpp
@@ -0,0 +1,1148 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Blend Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineBlendTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineUniqueRandomIterator.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuPlatform.hpp"
+#include "tcuTextureUtil.hpp"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+#include <cstring>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+bool isSupportedBlendFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
+{
+	VkFormatProperties formatProps;
+
+	VK_CHECK(instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps));
+
+	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
+		   (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
+}
+
+class BlendStateUniqueRandomIterator : public UniqueRandomIterator<VkPipelineColorBlendAttachmentState>
+{
+public:
+											BlendStateUniqueRandomIterator		(deUint32 numberOfCombinations, int seed);
+	virtual									~BlendStateUniqueRandomIterator		(void) {}
+	VkPipelineColorBlendAttachmentState		getIndexedValue	(deUint32 index);
+
+private:
+	const static VkBlend					m_blendFactors[];
+	const static VkBlendOp					m_blendOps[];
+
+	// Pre-calculated constants
+	const static deUint32					m_blendFactorsLength;
+	const static deUint32					m_blendFactorsLength2;
+	const static deUint32					m_blendFactorsLength3;
+	const static deUint32					m_blendFactorsLength4;
+	const static deUint32					m_blendOpsLength;
+
+	// Total number of cross-combinations of (srcBlendColor x destBlendColor x blendOpColor x srcBlendAlpha x destBlendAlpha x blendOpAlpha)
+	const static deUint32					m_totalBlendStates;
+};
+
+class BlendTest : public vkt::TestCase
+{
+public:
+	enum
+	{
+		QUAD_COUNT = 4
+	};
+
+	const static VkChannelFlags			s_channelWriteMasks[QUAD_COUNT];
+	const static tcu::Vec4				s_blendConst;
+
+										BlendTest				(tcu::TestContext&							testContext,
+																 const std::string&							name,
+																 const std::string&							description,
+																 const VkFormat								colorFormat,
+																 const VkPipelineColorBlendAttachmentState	blendStates[QUAD_COUNT]);
+	virtual								~BlendTest				(void);
+	virtual void						initPrograms			(SourceCollections& sourceCollections) const;
+	virtual TestInstance*				createInstance			(Context& context) const;
+
+private:
+	const VkFormat						m_colorFormat;
+	VkPipelineColorBlendAttachmentState	m_blendStates[QUAD_COUNT];
+};
+
+class BlendTestInstance : public vkt::TestInstance
+{
+public:
+										BlendTestInstance		(Context& context, const VkFormat colorFormat, const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT]);
+	virtual								~BlendTestInstance		(void);
+	virtual tcu::TestStatus				iterate					(void);
+
+private:
+	static float						getNormChannelThreshold	(const tcu::TextureFormat& format, int numBits);
+	static tcu::Vec4					getFormatThreshold		(const tcu::TextureFormat& format);
+	tcu::TestStatus						verifyImage				(void);
+
+	VkPipelineColorBlendAttachmentState	m_blendStates[BlendTest::QUAD_COUNT];
+
+	const tcu::IVec2					m_renderSize;
+	const VkFormat						m_colorFormat;
+
+	VkImageCreateInfo					m_colorImageCreateInfo;
+	Move<VkImage>						m_colorImage;
+	de::MovePtr<Allocation>				m_colorImageAlloc;
+	Move<VkImageView>					m_colorAttachmentView;
+	Move<VkRenderPass>					m_renderPass;
+	Move<VkFramebuffer>					m_framebuffer;
+
+	Move<VkShaderModule>				m_vertexShaderModule;
+	Move<VkShaderModule>				m_fragmentShaderModule;
+	Move<VkShader>						m_vertexShader;
+	Move<VkShader>						m_fragmentShader;
+
+	Move<VkBuffer>						m_vertexBuffer;
+	std::vector<Vertex4RGBA>			m_vertices;
+	de::MovePtr<Allocation>				m_vertexBufferAlloc;
+
+	Move<VkPipelineLayout>				m_pipelineLayout;
+	Move<VkPipeline>					m_graphicsPipelines[BlendTest::QUAD_COUNT];
+
+	Move<VkCmdPool>						m_cmdPool;
+	Move<VkCmdBuffer>					m_cmdBuffer;
+
+	Move<VkFence>						m_fence;
+};
+
+
+// BlendStateUniqueRandomIterator
+
+const VkBlend BlendStateUniqueRandomIterator::m_blendFactors[] =
+{
+	VK_BLEND_ZERO,
+	VK_BLEND_ONE,
+	VK_BLEND_SRC_COLOR,
+	VK_BLEND_ONE_MINUS_SRC_COLOR,
+	VK_BLEND_DEST_COLOR,
+	VK_BLEND_ONE_MINUS_DEST_COLOR,
+	VK_BLEND_SRC_ALPHA,
+	VK_BLEND_ONE_MINUS_SRC_ALPHA,
+	VK_BLEND_DEST_ALPHA,
+	VK_BLEND_ONE_MINUS_DEST_ALPHA,
+	VK_BLEND_CONSTANT_COLOR,
+	VK_BLEND_ONE_MINUS_CONSTANT_COLOR,
+	VK_BLEND_CONSTANT_ALPHA,
+	VK_BLEND_ONE_MINUS_CONSTANT_ALPHA,
+	VK_BLEND_SRC_ALPHA_SATURATE
+};
+
+const VkBlendOp BlendStateUniqueRandomIterator::m_blendOps[] =
+{
+	VK_BLEND_OP_ADD,
+	VK_BLEND_OP_SUBTRACT,
+	VK_BLEND_OP_REVERSE_SUBTRACT,
+	VK_BLEND_OP_MIN,
+	VK_BLEND_OP_MAX
+};
+
+const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength		= DE_LENGTH_OF_ARRAY(m_blendFactors);
+const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength2	= m_blendFactorsLength * m_blendFactorsLength;
+const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength3	= m_blendFactorsLength2 * m_blendFactorsLength;
+const deUint32 BlendStateUniqueRandomIterator::m_blendFactorsLength4	= m_blendFactorsLength3 * m_blendFactorsLength;
+const deUint32 BlendStateUniqueRandomIterator::m_blendOpsLength			= DE_LENGTH_OF_ARRAY(m_blendOps);
+const deUint32 BlendStateUniqueRandomIterator::m_totalBlendStates		= m_blendFactorsLength4 * m_blendOpsLength * m_blendOpsLength;
+
+
+BlendStateUniqueRandomIterator::BlendStateUniqueRandomIterator (deUint32 numberOfCombinations, int seed)
+	: UniqueRandomIterator<VkPipelineColorBlendAttachmentState>(numberOfCombinations, m_totalBlendStates, seed)
+{
+}
+
+VkPipelineColorBlendAttachmentState BlendStateUniqueRandomIterator::getIndexedValue (deUint32 index)
+{
+	const deUint32		blendOpAlphaIndex			= index / (m_blendFactorsLength4 * m_blendOpsLength);
+	const deUint32		blendOpAlphaSeqIndex		= blendOpAlphaIndex * (m_blendFactorsLength4 * m_blendOpsLength);
+
+	const deUint32		destBlendAlphaIndex			= (index - blendOpAlphaSeqIndex) / (m_blendFactorsLength3 * m_blendOpsLength);
+	const deUint32		destBlendAlphaSeqIndex		= destBlendAlphaIndex * (m_blendFactorsLength3 * m_blendOpsLength);
+
+	const deUint32		srcBlendAlphaIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex) / (m_blendFactorsLength2 * m_blendOpsLength);
+	const deUint32		srcBlendAlphaSeqIndex		= srcBlendAlphaIndex * (m_blendFactorsLength2 * m_blendOpsLength);
+
+	const deUint32		blendOpColorIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex) / m_blendFactorsLength2;
+	const deUint32		blendOpColorSeqIndex		= blendOpColorIndex * m_blendFactorsLength2;
+
+	const deUint32		destBlendColorIndex			= (index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex - blendOpColorSeqIndex) / m_blendFactorsLength;
+	const deUint32		destBlendColorSeqIndex		= destBlendColorIndex * m_blendFactorsLength;
+
+	const deUint32		srcBlendColorIndex			= index - blendOpAlphaSeqIndex - destBlendAlphaSeqIndex - srcBlendAlphaSeqIndex - blendOpColorSeqIndex - destBlendColorSeqIndex;
+
+	const VkPipelineColorBlendAttachmentState blendAttachmentState =
+	{
+		true,																			// VkBool32			blendEnable;
+		m_blendFactors[srcBlendColorIndex],												// VkBlend			srcBlendColor;
+		m_blendFactors[destBlendColorIndex],											// VkBlend			destBlendColor;
+		m_blendOps[blendOpColorIndex],													// VkBlendOp		blendOpColor;
+		m_blendFactors[srcBlendAlphaIndex],												// VkBlend			srcBlendAlpha;
+		m_blendFactors[destBlendAlphaIndex],											// VkBlend			destBlendAlpha;
+		m_blendOps[blendOpAlphaIndex],													// VkBlendOp		blendOpAlpha;
+		VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT | VK_CHANNEL_A_BIT		// VkChannelFlags	channelWriteMask;
+	};
+
+	return blendAttachmentState;
+}
+
+
+// BlendTest
+
+const VkChannelFlags	BlendTest::s_channelWriteMasks[BlendTest::QUAD_COUNT] = { VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT,	// Pair of channels: R & G
+																				  VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT,	// Pair of channels: G & B
+																				  VK_CHANNEL_B_BIT | VK_CHANNEL_A_BIT,	// Pair of channels: B & A
+																				  VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT | VK_CHANNEL_A_BIT };	// All channels
+
+const tcu::Vec4			BlendTest::s_blendConst = tcu::Vec4(0.1f, 0.2f, 0.3f, 0.4f);
+
+BlendTest::BlendTest (tcu::TestContext&								testContext,
+					  const std::string&							name,
+					  const std::string&							description,
+					  const VkFormat								colorFormat,
+					  const VkPipelineColorBlendAttachmentState		blendStates[QUAD_COUNT])
+	: vkt::TestCase	(testContext, name, description)
+	, m_colorFormat(colorFormat)
+{
+	deMemcpy(m_blendStates, blendStates, sizeof(VkPipelineColorBlendAttachmentState) * QUAD_COUNT);
+}
+
+BlendTest::~BlendTest (void)
+{
+}
+
+TestInstance* BlendTest::createInstance(Context& context) const
+{
+	return new BlendTestInstance(context, m_colorFormat, m_blendStates);
+}
+
+void BlendTest::initPrograms (SourceCollections& sourceCollections) const
+{
+	std::ostringstream fragmentSource;
+
+	sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
+		"#version 310 es\n"
+		"layout(location = 0) in highp vec4 position;\n"
+		"layout(location = 1) in highp vec4 color;\n"
+		"layout(location = 0) out highp vec4 vtxColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	gl_Position = position;\n"
+		"	vtxColor = color;\n"
+		"}\n");
+
+	fragmentSource << "#version 310 es\n"
+		"layout(location = 0) in highp vec4 vtxColor;\n"
+		"layout(location = 0) out highp vec4 fragColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	fragColor = vtxColor;\n"
+		"}\n";
+
+	sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(fragmentSource.str());
+}
+
+
+// BlendTestInstance
+
+BlendTestInstance::BlendTestInstance (Context&									context,
+									  const VkFormat							colorFormat,
+									  const VkPipelineColorBlendAttachmentState	blendStates[BlendTest::QUAD_COUNT])
+	: vkt::TestInstance	(context)
+	, m_renderSize		(32, 32)
+	, m_colorFormat		(colorFormat)
+{
+	const DeviceInterface&		vk					= m_context.getDeviceInterface();
+	const VkDevice				vkDevice			= m_context.getDevice();
+	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
+	SimpleAllocator				memAlloc			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+
+	// Copy depth operators
+	deMemcpy(m_blendStates, blendStates, sizeof(VkPipelineColorBlendAttachmentState) * BlendTest::QUAD_COUNT);
+
+	// Create color image
+	{
+		if (!isSupportedBlendFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_colorFormat))
+			throw tcu::NotSupportedError(std::string("Unsupported color blending format: ") + getFormatName(m_colorFormat));
+
+		const VkImageCreateInfo	colorImageParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType		sType;
+			DE_NULL,																	// const void*			pNext;
+			VK_IMAGE_TYPE_2D,															// VkImageType			imageType;
+			m_colorFormat,																// VkFormat				format;
+			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D			extent;
+			1u,																			// deUint32				mipLevels;
+			1u,																			// deUint32				arraySize;
+			1u,																			// deUint32				samples;
+			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling		tiling;
+			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	// VkImageUsageFlags	usage;
+			0u,																			// VkImageCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode		sharingMode;
+			1u,																			// deUint32				queueFamilyCount;
+			&queueFamilyIndex,															// const deUint32*		pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout		initialLayout;
+		};
+
+		m_colorImageCreateInfo	= colorImageParams;
+		m_colorImage			= createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+		// Allocate and bind color image memory
+		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+	}
+
+	// Create color attachment view
+	{
+		const VkImageViewCreateInfo colorAttachmentViewParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			*m_colorImage,										// VkImage						image;
+			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType				viewType;
+			m_colorFormat,										// VkFormat						format;
+			getFormatChannelMapping(m_colorFormat),				// VkChannelMapping				channels;
+			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },		// VkImageSubresourceRange		subresourceRange;
+			0u													// VkImageViewCreateFlags		flags;
+		};
+
+		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+	}
+
+	// Create render pass
+	{
+		const VkAttachmentDescription colorAttachmentDescription =
+		{
+			VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			m_colorFormat,										// VkFormat						format;
+			1u,													// 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;
+			0u,													// VkAttachmentDescriptionFlags	flags;
+		};
+
+		const VkAttachmentReference colorAttachmentReference =
+		{
+			0u,													// deUint32			attachment;
+			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
+		};
+
+		const VkAttachmentReference depthStencilAttachmentReference =
+		{
+			VK_ATTACHMENT_UNUSED,								// deUint32			attachment;
+			VK_IMAGE_LAYOUT_UNDEFINED							// VkImageLayout	layout;
+		};
+
+		const VkSubpassDescription subpassDescription =
+		{
+			VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,				// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint			pipelineBindPoint;
+			0u,													// VkSubpassDescriptionFlags	flags;
+			0u,													// deUint32						inputCount;
+			DE_NULL,											// constVkAttachmentReference*	inputAttachments;
+			1u,													// deUint32						colorCount;
+			&colorAttachmentReference,							// constVkAttachmentReference*	pColorAttachments;
+			DE_NULL,											// constVkAttachmentReference*	pResolveAttachments;
+			depthStencilAttachmentReference,					// VkAttachmentReference		depthStencilAttachment;
+			0u,													// deUint32						preserveCount;
+			DE_NULL												// constVkAttachmentReference*	pPreserveAttachments;
+		};
+
+		const VkRenderPassCreateInfo renderPassParams =
+		{
+			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
+			DE_NULL,											// const void*						pNext;
+			1u,													// deUint32							attachmentCount;
+			&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
+			1u,													// deUint32							subpassCount;
+			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
+			0u,													// deUint32							dependencyCount;
+			DE_NULL												// const VkSubpassDependency*		pDependencies;
+		};
+
+		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+	}
+
+	// Create framebuffer
+	{
+		const VkFramebufferCreateInfo framebufferParams =
+		{
+			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,											// const void*			pNext;
+			*m_renderPass,										// VkRenderPass			renderPass;
+			1u,													// deUint32				attachmentCount;
+			&m_colorAttachmentView.get(),						// const VkImageView*	pAttachments;
+			(deUint32)m_renderSize.x(),							// deUint32				width;
+			(deUint32)m_renderSize.y(),							// deUint32				height;
+			1u													// deUint32				layers;
+		};
+
+		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+	}
+
+	// Create shaders
+	{
+		m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+		m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+		const VkShaderCreateInfo vertexShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_vertexShaderModule,							// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_VERTEX							// VkShaderStage		stage;
+		};
+
+		const VkShaderCreateInfo fragmentShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_fragmentShaderModule,						// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_FRAGMENT						// VkShaderStage		stage;
+		};
+
+		m_vertexShader		= createShader(vk, vkDevice, &vertexShaderParams);
+		m_fragmentShader	= createShader(vk, vkDevice, &fragmentShaderParams);
+	}
+
+	// Create pipeline layout
+	{
+		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			0u,													// deUint32						descriptorSetCount;
+			DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
+			0u,													// deUint32						pushConstantRangeCount;
+			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
+		};
+
+		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+	}
+
+	// Create pipeline
+	{
+		const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+		{
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_VERTEX,										// VkShaderStage				stage;
+				*m_vertexShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			},
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_FRAGMENT,									// VkShaderStage				stage;
+				*m_fragmentShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			}
+		};
+
+		const VkVertexInputBindingDescription vertexInputBindingDescription =
+		{
+			0u,									// deUint32					binding;
+			sizeof(Vertex4RGBA),				// deUint32					strideInBytes;
+			VK_VERTEX_INPUT_STEP_RATE_VERTEX	// VkVertexInputStepRate	stepRate;
+		};
+
+		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[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;
+				(deUint32)(sizeof(float) * 4),	// deUint32	offsetInBytes;
+			}
+		};
+
+		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
+			DE_NULL,														// const void*								pNext;
+			1u,																// deUint32									bindingCount;
+			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
+			2u,																// deUint32									attributeCount;
+			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+		};
+
+		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// VkPrimitiveTopology	topology;
+			false															// VkBool32				primitiveRestartEnable;
+		};
+
+		const VkViewport viewport =
+		{
+			0.0f,						// float	originX;
+			0.0f,						// float	originY;
+			(float)m_renderSize.x(),	// float	width;
+			(float)m_renderSize.y(),	// float	height;
+			0.0f,						// float	minDepth;
+			1.0f						// float	maxDepth;
+		};
+
+		const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+		const VkPipelineViewportStateCreateInfo viewportStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			1u,																// deUint32				viewportCount;
+			&viewport,														// const VkViewport*	pViewports;
+			1u,																// deUint32				scissorCount;
+			&scissor														// const VkRect2D*		pScissors;
+		};
+
+		const VkPipelineRasterStateCreateInfo rasterStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,			// VkStructureType	sType;
+			DE_NULL,														// const void*		pNext;
+			false,															// VkBool32			depthClipEnable;
+			false,															// VkBool32			rasterizerDiscardEnable;
+			VK_FILL_MODE_SOLID,												// VkFillMode		fillMode;
+			VK_CULL_MODE_NONE,												// VkCullMode		cullMode;
+			VK_FRONT_FACE_CCW,												// VkFrontFace		frontFace;
+			false,															// VkBool32			depthBiasEnable;
+			0.0f,															// float			depthBias;
+			0.0f,															// float			depthBiasClamp;
+			0.0f,															// float			slopeScaledDepthBias;
+			1.0f															// float			lineWidth;
+		};
+
+		const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,													// const void*			pNext;
+			1u,															// deUint32				rasterSamples;
+			false,														// VkBool32				sampleShadingEnable;
+			0.0f,														// float				minSampleShading;
+			DE_NULL														// const VkSampleMask*	sampleMask;
+		};
+
+		const VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType	sType;
+			DE_NULL,													// const void*		pNext;
+			false,														// VkBool32			depthTestEnable;
+			false,														// VkBool32			depthWriteEnable;
+			VK_COMPARE_OP_LESS,											// VkCompareOp		depthCompareOp;
+			false,														// VkBool32			depthBoundsTestEnable;
+			false,														// VkBool32			stencilTestEnable;
+			// VkStencilOpState	front;
+			{
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilFailOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilPassOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilDepthFailOp;
+				VK_COMPARE_OP_NEVER,	// VkCompareOp	stencilCompareOp;
+				0u,						// deUint32		stencilCompareMask;
+				0u,						// deUint32		stencilWriteMask;
+				0u						// deUint32		stencilReference;
+			},
+			// VkStencilOpState	back;
+			{
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilFailOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilPassOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilDepthFailOp;
+				VK_COMPARE_OP_NEVER,	// VkCompareOp	stencilCompareOp;
+				0u,						// deUint32		stencilCompareMask;
+				0u,						// deUint32		stencilWriteMask;
+				0u						// deUint32		stencilReference;
+			},
+			-1.0f,														// float			minDepthBounds;
+			+1.0f														// float			maxDepthBounds;
+		};
+
+		// The color blend attachment will be set up before creating the graphics pipeline.
+		VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
+			DE_NULL,													// const void*									pNext;
+			false,														// VkBool32										alphaToCoverageEnable;
+			false,														// VkBool32										alphaToOneEnable;
+			false,														// VkBool32										logicOpEnable;
+			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
+			1u,															// deUint32										attachmentCount;
+			DE_NULL,													// const VkPipelineColorBlendAttachmentState*	pAttachments;
+			{															// float										blendConst[4];
+				BlendTest::s_blendConst.x(),
+				BlendTest::s_blendConst.y(),
+				BlendTest::s_blendConst.z(),
+				BlendTest::s_blendConst.w()
+			}
+		};
+
+		const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,		// VkStructureType			sType;
+			DE_NULL,													// const void*				pNext;
+			0u,															// deUint32					dynamicStateCount;
+			DE_NULL														// const VkDynamicState*	pDynamicStates;
+		};
+
+		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+		{
+			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
+			DE_NULL,											// const void*										pNext;
+			2u,													// deUint32											stageCount;
+			shaderStageParams,									// const VkPipelineShaderStageCreateInfo*			pStages;
+			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
+			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
+			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
+			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
+			&rasterStateParams,									// const VkPipelineRasterStateCreateInfo*			pRasterState;
+			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
+			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
+			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
+			&dynamicStateParams,								// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
+			0u,													// VkPipelineCreateFlags							flags;
+			*m_pipelineLayout,									// VkPipelineLayout									layout;
+			*m_renderPass,										// VkRenderPass										renderPass;
+			0u,													// deUint32											subpass;
+			0u,													// VkPipeline										basePipelineHandle;
+			0u													// deInt32											basePipelineIndex;
+		};
+
+		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+		{
+			colorBlendStateParams.pAttachments	= &m_blendStates[quadNdx];
+			m_graphicsPipelines[quadNdx]		= createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+		}
+	}
+
+	// Create vertex buffer
+	{
+		const VkBufferCreateInfo vertexBufferParams =
+		{
+			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			1024u,										// VkDeviceSize			size;
+			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
+			0u,											// VkBufferCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
+			1u,											// deUint32				queueFamilyCount;
+			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
+		};
+
+		m_vertices			= createOverlappingQuads();
+		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
+		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+		// Adjust vertex colors
+		if (!isFloatFormat(m_colorFormat))
+		{
+			const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(mapVkFormat(m_colorFormat));
+			for (size_t vertexNdx = 0; vertexNdx < m_vertices.size(); vertexNdx++)
+				m_vertices[vertexNdx].color = (m_vertices[vertexNdx].color - formatInfo.lookupBias) / formatInfo.lookupScale;
+		}
+
+		// Upload vertex data
+		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+
+		const VkMappedMemoryRange flushRange =
+		{
+			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// VkStructureType	sType;
+			DE_NULL,								// const void*		pNext;
+			m_vertexBufferAlloc->getMemory(),		// VkDeviceMemory	mem;
+			m_vertexBufferAlloc->getOffset(),		// VkDeviceSize		offset;
+			vertexBufferParams.size					// VkDeviceSize		size;
+		};
+
+		vk.flushMappedMemoryRanges(vkDevice, 1, &flushRange);
+	}
+
+	// Create command pool
+	{
+		const VkCmdPoolCreateInfo cmdPoolParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			queueFamilyIndex,							// deUint32				queueFamilyIndex;
+			VK_CMD_POOL_CREATE_TRANSIENT_BIT			// VkCmdPoolCreateFlags	flags;
+		};
+
+		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+	}
+
+	// Create command buffer
+	{
+		const VkCmdBufferCreateInfo cmdBufferParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			*m_cmdPool,									// VkCmdPool				cmdPool;
+			VK_CMD_BUFFER_LEVEL_PRIMARY,				// VkCmdBufferLevel			level;
+			0u											// VkCmdBufferCreateFlags	flags;
+		};
+
+		const VkCmdBufferBeginInfo cmdBufferBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			0u,											// VkCmdBufferOptimizeFlags	flags;
+			0u,											// deUint32					subpass;
+			DE_NULL,									// VkRenderPass				renderPass;
+			DE_NULL										// VkFramebuffer			framebuffer;
+		};
+
+		const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
+
+		const VkRenderPassBeginInfo renderPassBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
+			DE_NULL,												// const void*			pNext;
+			*m_renderPass,											// VkRenderPass			renderPass;
+			*m_framebuffer,											// VkFramebuffer		framebuffer;
+			{ { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
+			1,														// deUint32				clearValueCount;
+			&attachmentClearValue									// const VkClearValue*	pClearValues;
+		};
+
+		m_cmdBuffer = createCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_RENDER_PASS_CONTENTS_INLINE);
+
+		const VkDeviceSize quadOffset = (m_vertices.size() / BlendTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
+
+		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+		{
+			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
+
+			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
+			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / BlendTest::QUAD_COUNT), 1, 0, 0);
+		}
+
+		vk.cmdEndRenderPass(*m_cmdBuffer);
+		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+	}
+
+	// Create fence
+	{
+		const VkFenceCreateInfo fenceParams =
+		{
+			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,								// const void*			pNext;
+			0u										// VkFenceCreateFlags	flags;
+		};
+
+		m_fence = createFence(vk, vkDevice, &fenceParams);
+	}
+}
+
+BlendTestInstance::~BlendTestInstance (void)
+{
+}
+
+tcu::TestStatus BlendTestInstance::iterate (void)
+{
+	const DeviceInterface&		vk			= m_context.getDeviceInterface();
+	const VkDevice				vkDevice	= m_context.getDevice();
+	const VkQueue				queue		= m_context.getUniversalQueue();
+
+	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+	VK_CHECK(vk.queueSubmit(queue, 1, &m_cmdBuffer.get(), *m_fence));
+	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
+
+	return verifyImage();
+}
+
+float BlendTestInstance::getNormChannelThreshold (const tcu::TextureFormat& format, int numBits)
+{
+	switch (tcu::getTextureChannelClass(format.type))
+	{
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << numBits) - 1);
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:	return BlendTest::QUAD_COUNT / static_cast<float>((1 << (numBits - 1)) - 1);
+		default:
+			break;
+	}
+
+	DE_ASSERT(false);
+	return 0.0f;
+}
+
+tcu::Vec4 BlendTestInstance::getFormatThreshold (const tcu::TextureFormat& format)
+{
+	using tcu::Vec4;
+	using tcu::TextureFormat;
+
+	Vec4 threshold(0.01f);
+
+	switch (format.type)
+	{
+		case TextureFormat::UNORM_BYTE_44:
+			threshold = Vec4(getNormChannelThreshold(format, 4), getNormChannelThreshold(format, 4), 1.0f, 1.0f);
+			break;
+
+		case TextureFormat::UNORM_SHORT_565:
+			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 6), getNormChannelThreshold(format, 5), 1.0f);
+			break;
+
+		case TextureFormat::UNORM_SHORT_555:
+			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 1.0f);
+			break;
+
+		case TextureFormat::UNORM_SHORT_4444:
+			threshold = Vec4(getNormChannelThreshold(format, 4));
+			break;
+
+		case TextureFormat::UNORM_SHORT_5551:
+			threshold = Vec4(getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), getNormChannelThreshold(format, 5), 0.1f);
+			break;
+
+		case TextureFormat::UNORM_INT_1010102_REV:
+		case TextureFormat::SNORM_INT_1010102_REV:
+			threshold = Vec4(getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), getNormChannelThreshold(format, 10), 0.1f);
+			break;
+
+		case TextureFormat::UNORM_INT8:
+		case TextureFormat::SNORM_INT8:
+			threshold = Vec4(getNormChannelThreshold(format, 8));
+			break;
+
+		case TextureFormat::UNORM_INT16:
+		case TextureFormat::SNORM_INT16:
+			threshold = Vec4(getNormChannelThreshold(format, 16));
+			break;
+
+		case TextureFormat::UNORM_INT32:
+		case TextureFormat::SNORM_INT32:
+			threshold = Vec4(getNormChannelThreshold(format, 32));
+			break;
+
+		case TextureFormat::HALF_FLOAT:
+			threshold = Vec4(0.005f);
+			break;
+
+		case TextureFormat::FLOAT:
+			threshold = Vec4(0.00001f);
+			break;
+
+		case TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
+			threshold = Vec4(0.02f, 0.02f, 0.02f, 1.0f);
+			break;
+
+		case TextureFormat::UNSIGNED_INT_999_E5_REV:
+			threshold = Vec4(0.05f, 0.05f, 0.05f, 1.0f);
+			break;
+
+		default:
+			DE_ASSERT(false);
+	}
+
+	// Return value matching the channel order specified by the format
+	if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA)
+		return threshold.swizzle(2, 1, 0, 3);
+	else
+		return threshold;
+}
+
+tcu::TestStatus BlendTestInstance::verifyImage (void)
+{
+	const tcu::TextureFormat	tcuColorFormat	= mapVkFormat(m_colorFormat);
+	const tcu::TextureFormat	tcuDepthFormat	= tcu::TextureFormat(); // Undefined depth/stencil format
+	const ColorVertexShader		vertexShader;
+	const ColorFragmentShader	fragmentShader	(tcuColorFormat, tcuDepthFormat);
+	const rr::Program			program			(&vertexShader, &fragmentShader);
+	ReferenceRenderer			refRenderer		(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+	bool						compareOk		= false;
+
+	// Render reference image
+	{
+		for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+		{
+			const VkPipelineColorBlendAttachmentState& blendState = m_blendStates[quadNdx];
+
+			// Set blend state
+			rr::RenderState renderState					(refRenderer.getViewportState());
+			renderState.fragOps.blendMode				= rr::BLENDMODE_STANDARD;
+			renderState.fragOps.blendRGBState.srcFunc	= mapVkBlend(blendState.srcBlendColor);
+			renderState.fragOps.blendRGBState.dstFunc	= mapVkBlend(blendState.destBlendColor);
+			renderState.fragOps.blendRGBState.equation	= mapVkBlendOp(blendState.blendOpColor);
+			renderState.fragOps.blendAState.srcFunc		= mapVkBlend(blendState.srcBlendAlpha);
+			renderState.fragOps.blendAState.dstFunc		= mapVkBlend(blendState.destBlendAlpha);
+			renderState.fragOps.blendAState.equation	= mapVkBlendOp(blendState.blendOpAlpha);
+			renderState.fragOps.blendColor				= BlendTest::s_blendConst;
+			renderState.fragOps.colorMask				= mapVkChannelFlags(BlendTest::s_channelWriteMasks[quadNdx]);
+
+			refRenderer.draw(renderState,
+							 rr::PRIMITIVETYPE_TRIANGLES,
+							 std::vector<Vertex4RGBA>(m_vertices.begin() + quadNdx * 6,
+													  m_vertices.begin() + (quadNdx + 1) * 6));
+		}
+	}
+
+
+	// Compare result with reference image
+	{
+		const DeviceInterface&				vk							= m_context.getDeviceInterface();
+		const VkDevice						vkDevice					= m_context.getDevice();
+		const VkQueue						queue						= m_context.getUniversalQueue();
+		const deUint32						queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
+		SimpleAllocator						allocator					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+		de::UniquePtr<tcu::TextureLevel>	result						(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
+		const tcu::Vec4						threshold					(getFormatThreshold(tcuColorFormat));
+
+		compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(),
+											   "FloatImageCompare",
+											   "Image comparison",
+											   refRenderer.getAccess(),
+											   result->getAccess(),
+											   threshold,
+											   tcu::COMPARE_LOG_RESULT);
+	}
+
+	if (compareOk)
+		return tcu::TestStatus::pass("Result image matches reference");
+	else
+		return tcu::TestStatus::fail("Image mismatch");
+}
+
+} // anonymous
+
+std::string getBlendStateName (const VkPipelineColorBlendAttachmentState& blendState)
+{
+	const char* shortBlendFactorNames[] =
+	{
+		"z",		// VK_BLEND_ZERO
+		"o",		// VK_BLEND_ONE
+		"sc",		// VK_BLEND_SRC_COLOR
+		"1msc",		// VK_BLEND_ONE_MINUS_SRC_COLOR
+		"dc",		// VK_BLEND_DEST_COLOR
+		"1mdc",		// VK_BLEND_ONE_MINUS_DEST_COLOR
+		"sa",		// VK_BLEND_SRC_ALPHA
+		"1msa",		// VK_BLEND_ONE_MINUS_SRC_ALPHA
+		"da",		// VK_BLEND_DEST_ALPHA
+		"1mda",		// VK_BLEND_ONE_MINUS_DEST_ALPHA
+		"cc",		// VK_BLEND_CONSTANT_COLOR
+		"1mcc",		// VK_BLEND_ONE_MINUS_CONSTANT_COLOR
+		"ca",		// VK_BLEND_CONSTANT_ALPHA
+		"1mca",		// VK_BLEND_ONE_MINUS_CONSTANT_ALPHA
+		"sas"		// VK_BLEND_SRC_ALPHA_SATURATE
+	};
+
+	const char* blendOpNames[] =
+	{
+		"add",		// VK_BLEND_OP_ADD
+		"sub",		// VK_BLEND_OP_SUBTRACT
+		"rsub",		// VK_BLEND_OP_REVERSE_SUBTRACT
+		"min",		// VK_BLEND_OP_MIN
+		"max",		// VK_BLEND_OP_MAX
+	};
+
+	std::ostringstream shortName;
+
+	shortName << "color_" << shortBlendFactorNames[blendState.srcBlendColor] << "_" << shortBlendFactorNames[blendState.destBlendColor] << "_" << blendOpNames[blendState.blendOpColor];
+	shortName << "_alpha_" << shortBlendFactorNames[blendState.srcBlendAlpha] << "_" << shortBlendFactorNames[blendState.destBlendAlpha] << "_" << blendOpNames[blendState.blendOpAlpha];
+
+	return shortName.str();
+}
+
+std::string getBlendStateSetName (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
+{
+	std::ostringstream name;
+
+	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+	{
+		name << getBlendStateName(blendStates[quadNdx]);
+
+		if (quadNdx < BlendTest::QUAD_COUNT - 1)
+			name << "-";
+	}
+
+	return name.str();
+}
+
+std::string getBlendStateSetDescription (const VkPipelineColorBlendAttachmentState blendStates[BlendTest::QUAD_COUNT])
+{
+	std::ostringstream description;
+
+	description << "Draws " << BlendTest::QUAD_COUNT << " quads with the following blend states:\n";
+
+	for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+		description << blendStates[quadNdx] << "\n";
+
+	return description.str();
+}
+
+std::string getFormatCaseName (VkFormat format)
+{
+	const std::string fullName = getFormatName(format);
+
+	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
+
+	return de::toLower(fullName.substr(10));
+}
+
+tcu::TestCaseGroup* createBlendTests (tcu::TestContext& testCtx)
+{
+	const deUint32 blendStatesPerFormat = 100 * BlendTest::QUAD_COUNT;
+
+	// Formats that are dEQP-compatible, non-integer and uncompressed
+	const VkFormat blendFormats[] =
+	{
+		VK_FORMAT_R4G4_UNORM,
+		VK_FORMAT_R4G4B4A4_UNORM,
+		VK_FORMAT_R5G6B5_UNORM,
+		VK_FORMAT_R5G5B5A1_UNORM,
+		VK_FORMAT_R8_UNORM,
+		VK_FORMAT_R8_SNORM,
+		VK_FORMAT_R8_SRGB,
+		VK_FORMAT_R8G8_UNORM,
+		VK_FORMAT_R8G8_SNORM,
+		VK_FORMAT_R8G8_SRGB,
+		VK_FORMAT_R8G8B8_UNORM,
+		VK_FORMAT_R8G8B8_SNORM,
+		VK_FORMAT_R8G8B8_SRGB,
+		VK_FORMAT_R8G8B8A8_UNORM,
+		VK_FORMAT_R8G8B8A8_SNORM,
+		VK_FORMAT_R8G8B8A8_SRGB,
+		VK_FORMAT_R10G10B10A2_UNORM,
+		VK_FORMAT_R16_UNORM,
+		VK_FORMAT_R16_SNORM,
+		VK_FORMAT_R16_SFLOAT,
+		VK_FORMAT_R16G16_UNORM,
+		VK_FORMAT_R16G16_SNORM,
+		VK_FORMAT_R16G16_SFLOAT,
+		VK_FORMAT_R16G16B16_UNORM,
+		VK_FORMAT_R16G16B16_SNORM,
+		VK_FORMAT_R16G16B16_SFLOAT,
+		VK_FORMAT_R16G16B16A16_UNORM,
+		VK_FORMAT_R16G16B16A16_SNORM,
+		VK_FORMAT_R16G16B16A16_SFLOAT,
+		VK_FORMAT_R32_SFLOAT,
+		VK_FORMAT_R32G32_SFLOAT,
+		VK_FORMAT_R32G32B32_SFLOAT,
+		VK_FORMAT_R32G32B32A32_SFLOAT,
+		VK_FORMAT_R11G11B10_UFLOAT,
+		VK_FORMAT_R9G9B9E5_UFLOAT,
+		VK_FORMAT_B4G4R4A4_UNORM,
+		VK_FORMAT_B5G5R5A1_UNORM,
+	};
+
+	de::MovePtr<tcu::TestCaseGroup>		blendTests		(new tcu::TestCaseGroup(testCtx, "blend", "Blend tests"));
+	de::MovePtr<tcu::TestCaseGroup>		formatTests		(new tcu::TestCaseGroup(testCtx, "format", "Uses different blend formats"));
+	BlendStateUniqueRandomIterator		blendStateItr	(blendStatesPerFormat, 123);
+
+	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(blendFormats); formatNdx++)
+	{
+		const VkFormat					format			= blendFormats[formatNdx];
+		de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
+																				getFormatCaseName(format).c_str(),
+																				(std::string("Uses format ") + getFormatName(format)).c_str()));
+		de::MovePtr<tcu::TestCaseGroup>	blendStateTests;
+		{
+			std::ostringstream blendStateDescription;
+			blendStateDescription << "Combines blend factors, operators and channel write masks. The constant color used in all tests is " << BlendTest::s_blendConst;
+			blendStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", blendStateDescription.str().c_str()));
+		}
+
+		blendStateItr.reset();
+
+		while (blendStateItr.hasNext())
+		{
+			VkPipelineColorBlendAttachmentState quadBlendConfigs[BlendTest::QUAD_COUNT];
+
+			for (int quadNdx = 0; quadNdx < BlendTest::QUAD_COUNT; quadNdx++)
+			{
+				quadBlendConfigs[quadNdx] = blendStateItr.next();
+				quadBlendConfigs[quadNdx].channelWriteMask = BlendTest::s_channelWriteMasks[quadNdx];
+			}
+
+			blendStateTests->addChild(new BlendTest(testCtx,
+													getBlendStateSetName(quadBlendConfigs),
+													getBlendStateSetDescription(quadBlendConfigs),
+													format,
+													quadBlendConfigs));
+		}
+		formatTest->addChild(blendStateTests.release());
+		formatTests->addChild(formatTest.release());
+	}
+	blendTests->addChild(formatTests.release());
+
+	return blendTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.hpp
new file mode 100644
index 0000000..7585e95
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEBLENDTESTS_HPP
+#define _VKTPIPELINEBLENDTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Blend Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createBlendTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEBLENDTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.cpp
new file mode 100644
index 0000000..32bc5c4
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.cpp
@@ -0,0 +1,147 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for clear values.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineClearUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "tcuTextureUtil.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+tcu::Vec4 defaultClearColor (const tcu::TextureFormat& format)
+{
+   if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
+       return defaultClearColorUnorm();
+   else
+   {
+       const tcu::TextureFormatInfo formatInfo = tcu::getTextureFormatInfo(format);
+       return (defaultClearColorUnorm() - formatInfo.lookupBias) / formatInfo.lookupScale;
+   }
+}
+
+tcu::IVec4 defaultClearColorInt (const tcu::TextureFormat& format)
+{
+	const tcu::TextureFormatInfo	formatInfo	= tcu::getTextureFormatInfo(format);
+	const tcu::Vec4					color		= (defaultClearColorUnorm() - formatInfo.lookupBias) / formatInfo.lookupScale;
+
+	const tcu::IVec4				result		((deInt32)deFloatRound(color.x()), (deInt32)deFloatRound(color.y()),
+												 (deInt32)deFloatRound(color.z()), (deInt32)deFloatRound(color.w()));
+
+	return result;
+}
+
+tcu::UVec4 defaultClearColorUint (const tcu::TextureFormat& format)
+{
+	const tcu::TextureFormatInfo	formatInfo	= tcu::getTextureFormatInfo(format);
+	const tcu::Vec4					color		= (defaultClearColorUnorm() - formatInfo.lookupBias) / formatInfo.lookupScale;
+
+	const	tcu::UVec4				result		((deUint32)deFloatRound(color.x()), (deUint32)deFloatRound(color.y()),
+												 (deUint32)deFloatRound(color.z()), (deUint32)deFloatRound(color.w()));
+
+	return result;
+}
+
+tcu::Vec4 defaultClearColorUnorm (void)
+{
+	return tcu::Vec4(0.39f, 0.58f, 0.93f, 1.0f);
+}
+
+float defaultClearDepth (void)
+{
+	return 1.0f;
+}
+
+deUint32 defaultClearStencil (void)
+{
+	return 0;
+}
+
+VkClearDepthStencilValue defaultClearDepthStencilValue (void)
+{
+	VkClearDepthStencilValue clearDepthStencilValue;
+	clearDepthStencilValue.depth	= defaultClearDepth();
+	clearDepthStencilValue.stencil	= defaultClearStencil();
+
+	return clearDepthStencilValue;
+}
+
+VkClearValue defaultClearValue (VkFormat clearFormat)
+{
+	VkClearValue clearValue;
+
+	if (isDepthStencilFormat(clearFormat))
+	{
+		const VkClearDepthStencilValue dsValue = defaultClearDepthStencilValue();
+		clearValue.depthStencil.stencil	= dsValue.stencil;
+		clearValue.depthStencil.depth	= dsValue.depth;
+	}
+	else
+	{
+		const tcu::TextureFormat tcuClearFormat = mapVkFormat(clearFormat);
+		if (isUintFormat(clearFormat))
+		{
+			const tcu::UVec4 defaultColor	= defaultClearColorUint(tcuClearFormat);
+			clearValue.color.uint32[0]			= defaultColor.x();
+			clearValue.color.uint32[1]			= defaultColor.y();
+			clearValue.color.uint32[2]			= defaultColor.z();
+			clearValue.color.uint32[3]			= defaultColor.w();
+		}
+		else if (isIntFormat(clearFormat))
+		{
+			const tcu::IVec4 defaultColor	= defaultClearColorInt(tcuClearFormat);
+			clearValue.color.int32[0]			= defaultColor.x();
+			clearValue.color.int32[1]			= defaultColor.y();
+			clearValue.color.int32[2]			= defaultColor.z();
+			clearValue.color.int32[3]			= defaultColor.w();
+		}
+		else
+		{
+			const tcu::Vec4 defaultColor	= defaultClearColor(tcuClearFormat);
+			clearValue.color.float32[0]			= defaultColor.x();
+			clearValue.color.float32[1]			= defaultColor.y();
+			clearValue.color.float32[2]			= defaultColor.z();
+			clearValue.color.float32[3]			= defaultColor.w();
+		}
+	}
+
+	return clearValue;
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.hpp
new file mode 100644
index 0000000..6383aca
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineClearUtil.hpp
@@ -0,0 +1,60 @@
+#ifndef _VKTPIPELINECLEARUTIL_HPP
+#define _VKTPIPELINECLEARUTIL_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for clear values.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTexture.hpp"
+#include "tcuVectorUtil.hpp"
+#include "vkDefs.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::Vec4						defaultClearColor				(const tcu::TextureFormat& format);
+tcu::IVec4						defaultClearColorInt			(const tcu::TextureFormat& format);
+tcu::UVec4						defaultClearColorUint			(const tcu::TextureFormat& format);
+tcu::Vec4						defaultClearColorUnorm			(void);
+float							defaultClearDepth				(void);
+deUint32						defaultClearStencil				(void);
+
+vk::VkClearDepthStencilValue	defaultClearDepthStencilValue	(void);
+vk::VkClearValue				defaultClearValue				(vk::VkFormat format);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINECLEARUTIL_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.cpp
new file mode 100644
index 0000000..ccb973e
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.cpp
@@ -0,0 +1,1081 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Depth Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineDepthTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deMemory.h"
+
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
+{
+	VkFormatProperties formatProps;
+
+	VK_CHECK(instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps));
+
+	return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u;
+}
+
+tcu::TestStatus testSupportsDepthStencilFormat (Context& context, VkFormat format)
+{
+	DE_ASSERT(vk::isDepthStencilFormat(format));
+
+	if (isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), format))
+		return tcu::TestStatus::pass("Format can be used in depth/stencil attachment");
+	else
+		return tcu::TestStatus::fail("Unsupported depth/stencil attachment format");
+}
+
+tcu::TestStatus testSupportsAtLeastOneDepthStencilFormat (Context& context, const std::vector<VkFormat> formats)
+{
+	std::ostringstream	supportedFormatsMsg;
+	bool				pass					= false;
+
+	DE_ASSERT(!formats.empty());
+
+	for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
+	{
+		const VkFormat format = formats[formatNdx];
+
+		DE_ASSERT(vk::isDepthStencilFormat(format));
+
+		if (isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), format))
+		{
+			pass = true;
+			supportedFormatsMsg << vk::getFormatName(format);
+
+			if (formatNdx < formats.size() - 1)
+				supportedFormatsMsg << ", ";
+		}
+	}
+
+	if (pass)
+		return tcu::TestStatus::pass(std::string("Supported depth/stencil formats: ") + supportedFormatsMsg.str());
+	else
+		return tcu::TestStatus::fail("All depth/stencil formats are unsupported");
+}
+
+class DepthTest : public vkt::TestCase
+{
+public:
+	enum
+	{
+		QUAD_COUNT = 4
+	};
+
+	static const float					quadDepths[QUAD_COUNT];
+
+										DepthTest				(tcu::TestContext&		testContext,
+																 const std::string&		name,
+																 const std::string&		description,
+																 const VkFormat			depthFormat,
+																 const VkCompareOp		depthCompareOps[QUAD_COUNT]);
+	virtual								~DepthTest				(void);
+	virtual void						initPrograms			(SourceCollections& programCollection) const;
+	virtual TestInstance*				createInstance			(Context& context) const;
+
+private:
+	const VkFormat						m_depthFormat;
+	VkCompareOp							m_depthCompareOps[QUAD_COUNT];
+};
+
+class DepthTestInstance : public vkt::TestInstance
+{
+public:
+										DepthTestInstance		(Context& context, const VkFormat depthFormat, const VkCompareOp depthCompareOps[DepthTest::QUAD_COUNT]);
+	virtual								~DepthTestInstance		(void);
+	virtual tcu::TestStatus				iterate					(void);
+
+private:
+	tcu::TestStatus						verifyImage				(void);
+
+private:
+	VkCompareOp							m_depthCompareOps[DepthTest::QUAD_COUNT];
+	const tcu::IVec2					m_renderSize;
+	const VkFormat						m_colorFormat;
+	const VkFormat						m_depthFormat;
+
+	Move<VkImage>						m_colorImage;
+	de::MovePtr<Allocation>				m_colorImageAlloc;
+	Move<VkImage>						m_depthImage;
+	de::MovePtr<Allocation>				m_depthImageAlloc;
+	Move<VkImageView>					m_colorAttachmentView;
+	Move<VkImageView>					m_depthAttachmentView;
+	Move<VkRenderPass>					m_renderPass;
+	Move<VkFramebuffer>					m_framebuffer;
+
+	Move<VkShaderModule>				m_vertexShaderModule;
+	Move<VkShaderModule>				m_fragmentShaderModule;
+	Move<VkShader>						m_vertexShader;
+	Move<VkShader>						m_fragmentShader;
+
+	Move<VkBuffer>						m_vertexBuffer;
+	std::vector<Vertex4RGBA>			m_vertices;
+	de::MovePtr<Allocation>				m_vertexBufferAlloc;
+
+	Move<VkPipelineLayout>				m_pipelineLayout;
+	Move<VkPipeline>					m_graphicsPipelines[DepthTest::QUAD_COUNT];
+
+	Move<VkCmdPool>						m_cmdPool;
+	Move<VkCmdBuffer>					m_cmdBuffer;
+
+	Move<VkFence>						m_fence;
+};
+
+const float DepthTest::quadDepths[QUAD_COUNT] =
+{
+	0.1f,
+	0.0f,
+	0.3f,
+	0.2f
+};
+
+DepthTest::DepthTest (tcu::TestContext&		testContext,
+					  const std::string&	name,
+					  const std::string&	description,
+					  const VkFormat		depthFormat,
+					  const VkCompareOp		depthCompareOps[QUAD_COUNT])
+	: vkt::TestCase	(testContext, name, description)
+	, m_depthFormat	(depthFormat)
+{
+	deMemcpy(m_depthCompareOps, depthCompareOps, sizeof(VkCompareOp) * QUAD_COUNT);
+}
+
+DepthTest::~DepthTest (void)
+{
+}
+
+TestInstance* DepthTest::createInstance (Context& context) const
+{
+	return new DepthTestInstance(context, m_depthFormat, m_depthCompareOps);
+}
+
+void DepthTest::initPrograms (SourceCollections& programCollection) const
+{
+	programCollection.glslSources.add("color_vert") << glu::VertexSource(
+		"#version 310 es\n"
+		"layout(location = 0) in vec4 position;\n"
+		"layout(location = 1) in vec4 color;\n"
+		"layout(location = 0) out highp vec4 vtxColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	gl_Position = position;\n"
+		"	vtxColor = color;\n"
+		"}\n");
+
+	programCollection.glslSources.add("color_frag") << glu::FragmentSource(
+		"#version 310 es\n"
+		"layout(location = 0) in highp vec4 vtxColor;\n"
+		"layout(location = 0) out highp vec4 fragColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	fragColor = vtxColor;\n"
+		"}\n");
+}
+
+DepthTestInstance::DepthTestInstance (Context&				context,
+									  const VkFormat		depthFormat,
+									  const VkCompareOp		depthCompareOps[DepthTest::QUAD_COUNT])
+	: vkt::TestInstance	(context)
+	, m_renderSize		(32, 32)
+	, m_colorFormat		(VK_FORMAT_R8G8B8A8_UNORM)
+	, m_depthFormat		(depthFormat)
+{
+	const DeviceInterface&		vk					= context.getDeviceInterface();
+	const VkDevice				vkDevice			= context.getDevice();
+	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+	SimpleAllocator				memAlloc			(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+	const VkChannelMapping		channelMappingRGBA	= { VK_CHANNEL_SWIZZLE_R, VK_CHANNEL_SWIZZLE_G, VK_CHANNEL_SWIZZLE_B, VK_CHANNEL_SWIZZLE_A };
+
+	// Copy depth operators
+	deMemcpy(m_depthCompareOps, depthCompareOps, sizeof(VkCompareOp) * DepthTest::QUAD_COUNT);
+
+	// Create color image
+	{
+		const VkImageCreateInfo colorImageParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType		sType;
+			DE_NULL,																	// const void*			pNext;
+			VK_IMAGE_TYPE_2D,															// VkImageType			imageType;
+			m_colorFormat,																// VkFormat				format;
+			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D			extent;
+			1u,																			// deUint32				mipLevels;
+			1u,																			// deUint32				arraySize;
+			1u,																			// deUint32				samples;
+			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling		tiling;
+			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	// VkImageUsageFlags	usage;
+			0u,																			// VkImageCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode		sharingMode;
+			1u,																			// deUint32				queueFamilyCount;
+			&queueFamilyIndex,															// const deUint32*		pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED,													// VkImageLayout		initialLayout;
+		};
+
+		m_colorImage			= createImage(vk, vkDevice, &colorImageParams);
+
+		// Allocate and bind color image memory
+		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+	}
+
+	// Create depth image
+	{
+		// Check format support
+		if (!isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_depthFormat))
+			throw tcu::NotSupportedError(std::string("Unsupported depth/stencil format: ") + getFormatName(m_depthFormat));
+
+		const VkImageCreateInfo depthImageParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			VK_IMAGE_TYPE_2D,								// VkImageType			imageType;
+			m_depthFormat,									// VkFormat				format;
+			{ m_renderSize.x(), m_renderSize.y(), 1u },		// VkExtent3D			extent;
+			1u,												// deUint32				mipLevels;
+			1u,												// deUint32				arraySize;
+			1u,												// deUint32				samples;
+			VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling		tiling;
+			VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,	// VkImageUsageFlags	usage;
+			0u,												// VkImageCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode		sharingMode;
+			1u,												// deUint32				queueFamilyCount;
+			&queueFamilyIndex,								// const deUint32*		pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout		initialLayout;
+		};
+
+		m_depthImage = createImage(vk, vkDevice, &depthImageParams);
+
+		// Allocate and bind depth image memory
+		m_depthImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_depthImage), MemoryRequirement::Any);
+		VK_CHECK(vk.bindImageMemory(vkDevice, *m_depthImage, m_depthImageAlloc->getMemory(), m_depthImageAlloc->getOffset()));
+	}
+
+	// Create color attachment view
+	{
+		const VkImageViewCreateInfo colorAttachmentViewParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// VkStructureType			sType;
+			DE_NULL,										// const void*				pNext;
+			*m_colorImage,									// VkImage					image;
+			VK_IMAGE_VIEW_TYPE_2D,							// VkImageViewType			viewType;
+			m_colorFormat,									// VkFormat					format;
+			channelMappingRGBA,							 	// VkChannelMapping			channels;
+			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },  // VkImageSubresourceRange	subresourceRange;
+			0u												// VkImageViewCreateFlags	flags;
+		};
+
+		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+	}
+
+	// Create depth attachment view
+	{
+		const VkImageViewCreateInfo depthAttachmentViewParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// VkStructureType			sType;
+			DE_NULL,										// const void*				pNext;
+			*m_depthImage,									// VkImage					image;
+			VK_IMAGE_VIEW_TYPE_2D,							// VkImageViewType			viewType;
+			m_depthFormat,									// VkFormat					format;
+			channelMappingRGBA,							 	// VkChannelMapping			channels;
+			{ VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u },  // VkImageSubresourceRange	subresourceRange;
+			0u												// VkImageViewCreateFlags	flags;
+		};
+
+		m_depthAttachmentView = createImageView(vk, vkDevice, &depthAttachmentViewParams);
+	}
+
+	// Create render pass
+	{
+		const VkAttachmentDescription colorAttachmentDescription =
+		{
+			VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			m_colorFormat,										// VkFormat						format;
+			1u,													// 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;
+			0u,													// VkAttachmentDescriptionFlags	flags;
+		};
+
+		const VkAttachmentDescription depthAttachmentDescription =
+		{
+			VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			m_depthFormat,										// VkFormat						format;
+			1u,													// deUint32						samples;
+			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp			loadOp;
+			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp			storeOp;
+			VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp			stencilLoadOp;
+			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp			stencilStoreOp;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout				initialLayout;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout				finalLayout;
+			0u,													// VkAttachmentDescriptionFlags	flags;
+		};
+
+		const VkAttachmentDescription attachments[2] =
+		{
+			colorAttachmentDescription,
+			depthAttachmentDescription
+		};
+
+		const VkAttachmentReference colorAttachmentReference =
+		{
+			0u,													// deUint32			attachment;
+			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
+		};
+
+		const VkAttachmentReference depthAttachmentReference =
+		{
+			1u,													// deUint32			attachment;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
+		};
+
+		const VkSubpassDescription subpassDescription =
+		{
+			VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,				// VkStructureType					sType;
+			DE_NULL,											// const void*						pNext;
+			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
+			0u,													// VkSubpassDescriptionFlags		flags;
+			0u,													// deUint32							inputCount;
+			DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
+			1u,													// deUint32							colorCount;
+			&colorAttachmentReference,							// const VkAttachmentReference*		pColorAttachments;
+			DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
+			depthAttachmentReference,							// VkAttachmentReference			depthStencilAttachment;
+			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;
+			2u,													// deUint32							attachmentCount;
+			attachments,										// const VkAttachmentDescription*	pAttachments;
+			1u,													// deUint32							subpassCount;
+			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
+			0u,													// deUint32							dependencyCount;
+			DE_NULL												// const VkSubpassDependency*		pDependencies;
+		};
+
+		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+	}
+
+	// Create framebuffer
+	{
+		const VkImageView attachmentBindInfos[2] =
+		{
+			*m_colorAttachmentView,
+			*m_depthAttachmentView,
+		};
+
+		const VkFramebufferCreateInfo framebufferParams =
+		{
+			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			*m_renderPass,										// VkRenderPass					renderPass;
+			2u,													// deUint32						attachmentCount;
+			attachmentBindInfos,								// const VkImageView*			pAttachments;
+			(deUint32)m_renderSize.x(),							// deUint32						width;
+			(deUint32)m_renderSize.y(),							// deUint32						height;
+			1u													// deUint32						layers;
+		};
+
+		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+	}
+
+	// Create pipeline layout
+	{
+		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			0u,													// deUint32						descriptorSetCount;
+			DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
+			0u,													// deUint32						pushConstantRangeCount;
+			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
+		};
+
+		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+	}
+
+	// Create shaders
+	{
+		m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+		m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+		const VkShaderCreateInfo vertexShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_vertexShaderModule,							// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_VERTEX,							// VkShaderStage		stage;
+		};
+
+		const VkShaderCreateInfo fragmentShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_fragmentShaderModule,						// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_FRAGMENT,						// VkShaderStage		stage;
+		};
+
+		m_vertexShader		= createShader(vk, vkDevice, &vertexShaderParams);
+		m_fragmentShader	= createShader(vk, vkDevice, &fragmentShaderParams);
+	}
+
+	// Create pipeline
+	{
+		const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+		{
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_VERTEX,										// VkShaderStage				stage;
+				*m_vertexShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			},
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_FRAGMENT,									// VkShaderStage				stage;
+				*m_fragmentShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			}
+		};
+
+		const VkVertexInputBindingDescription vertexInputBindingDescription =
+		{
+			0u,									// deUint32					binding;
+			sizeof(Vertex4RGBA),				// deUint32					strideInBytes;
+			VK_VERTEX_INPUT_STEP_RATE_VERTEX	// VkVertexInputStepRate	stepRate;
+		};
+
+		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[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;
+				DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32	offsetInBytes;
+			}
+		};
+
+		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
+			DE_NULL,														// const void*								pNext;
+			1u,																// deUint32									bindingCount;
+			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
+			2u,																// deUint32									attributeCount;
+			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+		};
+
+		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// VkPrimitiveTopology	topology;
+			false															// VkBool32				primitiveRestartEnable;
+		};
+
+		const VkViewport viewport =
+		{
+			0.0f,						// float	originX;
+			0.0f,						// float	originY;
+			(float)m_renderSize.x(),	// float	width;
+			(float)m_renderSize.y(),	// float	height;
+			0.0f,						// float	minDepth;
+			1.0f						// float	maxDepth;
+		};
+		const VkRect2D scissor =
+		{
+			{ 0, 0 },												// VkOffset2D  offset;
+			{ m_renderSize.x(), m_renderSize.y() }					// VkExtent2D  extent;
+		};
+		const VkPipelineViewportStateCreateInfo viewportStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			1u,																// deUint32				viewportCount;
+			&viewport,														// const VkViewport*	pViewports;
+			1u,																// deUint32				scissorCount;
+			&scissor														// const VkRect2D*		pScissors;
+		};
+
+		const VkPipelineRasterStateCreateInfo rasterStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,			// VkStructureType	sType;
+			DE_NULL,														// const void*		pNext;
+			false,															// VkBool32			depthClipEnable;
+			false,															// VkBool32			rasterizerDiscardEnable;
+			VK_FILL_MODE_SOLID,												// VkFillMode		fillMode;
+			VK_CULL_MODE_NONE,												// VkCullMode		cullMode;
+			VK_FRONT_FACE_CCW,												// VkFrontFace		frontFace;
+			VK_FALSE,														// VkBool32			depthBiasEnable;
+			0.0f,															// float			depthBias;
+			0.0f,															// float			depthBiasClamp;
+			0.0f,															// float			slopeScaledDepthBias;
+			1.0f,															// float			lineWidth;
+		};
+
+		const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+		{
+			false,																		// VkBool32			blendEnable;
+			VK_BLEND_ONE,																// VkBlend			srcBlendColor;
+			VK_BLEND_ZERO,																// VkBlend			destBlendColor;
+			VK_BLEND_OP_ADD,															// VkBlendOp		blendOpColor;
+			VK_BLEND_ONE,																// VkBlend			srcBlendAlpha;
+			VK_BLEND_ZERO,																// VkBlend			destBlendAlpha;
+			VK_BLEND_OP_ADD,															// VkBlendOp		blendOpAlpha;
+			VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT | VK_CHANNEL_A_BIT	// VkChannelFlags	channelWriteMask;
+		};
+
+		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
+			DE_NULL,													// const void*									pNext;
+			false,														// VkBool32										alphaToCoverageEnable;
+			false,														// VkBool32										alphaToOneEnable;
+			false,														// VkBool32										logicOpEnable;
+			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
+			1u,															// deUint32										attachmentCount;
+			&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
+			{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConst[4];
+		};
+
+		const VkPipelineMultisampleStateCreateInfo	multisampleStateParams	=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,													// const void*			pNext;
+			1u,															// deUint32				rasterSamples;
+			false,														// VkBool32				sampleShadingEnable;
+			0.0f,														// float				minSampleShading;
+			DE_NULL														// const VkSampleMask*	pSampleMask;
+		};
+
+		const VkPipelineDynamicStateCreateInfo	dynamicStateParams		=
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,		// VkStructureType			sType;
+			DE_NULL,													// const void*				pNext;
+			0u,															// deUint32					dynamicStateCount;
+			DE_NULL														// const VkDynamicState*	pDynamicStates;
+		};
+
+		VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType	sType;
+			DE_NULL,													// const void*		pNext;
+			true,														// VkBool32			depthTestEnable;
+			true,														// VkBool32			depthWriteEnable;
+			VK_COMPARE_OP_LESS,											// VkCompareOp		depthCompareOp;
+			false,														// VkBool32			depthBoundsTestEnable;
+			false,														// VkBool32			stencilTestEnable;
+			// VkStencilOpState	front;
+			{
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilFailOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilPassOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilDepthFailOp;
+				VK_COMPARE_OP_NEVER,	// VkCompareOp	stencilCompareOp;
+				0u,						// deUint32		stencilCompareMask;
+				0u,						// deUint32		stencilWriteMask;
+				0u,						// deUint32		stencilReference;
+			},
+			// VkStencilOpState	back;
+			{
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilFailOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilPassOp;
+				VK_STENCIL_OP_KEEP,		// VkStencilOp	stencilDepthFailOp;
+				VK_COMPARE_OP_NEVER,	// VkCompareOp	stencilCompareOp;
+				0u,						// deUint32		stencilCompareMask;
+				0u,						// deUint32		stencilWriteMask;
+				0u,						// deUint32		stencilReference;
+			},
+			-1.0f,														// float			minDepthBounds;
+			+1.0f,														// float			maxDepthBounds;
+		};
+
+		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+		{
+			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
+			DE_NULL,											// const void*										pNext;
+			2u,													// deUint32											stageCount;
+			shaderStageParams,									// const VkPipelineShaderStageCreateInfo*			pStages;
+			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
+			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
+			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
+			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
+			&rasterStateParams,									// const VkPipelineRasterStateCreateInfo*			pRasterState;
+			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
+			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
+			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
+			&dynamicStateParams,								// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
+			0u,													// VkPipelineCreateFlags							flags;
+			*m_pipelineLayout,									// VkPipelineLayout									layout;
+			*m_renderPass,										// VkRenderPass										renderPass;
+			0u,													// deUint32											subpass;
+			0u,													// VkPipeline										basePipelineHandle;
+			0u													// deInt32											basePipelineIndex;
+		};
+
+		for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+		{
+			depthStencilStateParams.depthCompareOp	= depthCompareOps[quadNdx];
+			m_graphicsPipelines[quadNdx]			= createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+		}
+	}
+
+	// Create vertex buffer
+	{
+		const VkBufferCreateInfo vertexBufferParams =
+		{
+			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			1024u,										// VkDeviceSize			size;
+			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
+			0u,											// VkBufferCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
+			1u,											// deUint32				queueFamilyCount;
+			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
+		};
+
+		m_vertices			= createOverlappingQuads();
+		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
+		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+		// Adjust depths
+		for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+			for (int vertexNdx = 0; vertexNdx < 6; vertexNdx++)
+				m_vertices[quadNdx * 6 + vertexNdx].position.z() = DepthTest::quadDepths[quadNdx];
+
+		// Load vertices into vertex buffer
+		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+		flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
+	}
+
+	// Create command pool
+	{
+		const VkCmdPoolCreateInfo cmdPoolParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			queueFamilyIndex,							// deUint32				queueFamilyIndex;
+			VK_CMD_POOL_CREATE_TRANSIENT_BIT			// VkCmdPoolCreateFlags	flags;
+		};
+
+		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+	}
+
+	// Create command buffer
+	{
+		const VkCmdBufferCreateInfo cmdBufferParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			*m_cmdPool,									// VkCmdPool				cmdPool;
+			VK_CMD_BUFFER_LEVEL_PRIMARY,				// VkCmdBufferLevel			level;
+			0u											// VkCmdBufferCreateFlags	flags;
+		};
+
+		const VkCmdBufferBeginInfo cmdBufferBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			0u,											// VkCmdBufferOptimizeFlags	flags;
+			DE_NULL,									// VkRenderPass				renderPass;
+			0u,											// deUint32					subpass;
+			DE_NULL										// VkFramebuffer			framebuffer;
+		};
+
+		const VkClearValue attachmentClearValues[2] =
+		{
+			defaultClearValue(m_colorFormat),
+			defaultClearValue(m_depthFormat),
+		};
+
+		const VkRenderPassBeginInfo renderPassBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
+			DE_NULL,												// const void*			pNext;
+			*m_renderPass,											// VkRenderPass			renderPass;
+			*m_framebuffer,											// VkFramebuffer		framebuffer;
+			{ { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
+			2,														// deUint32				clearValueCount;
+			attachmentClearValues									// const VkClearValue*	pClearValues;
+		};
+
+		m_cmdBuffer = createCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_RENDER_PASS_CONTENTS_INLINE);
+
+		const VkDeviceSize		quadOffset		= (m_vertices.size() / DepthTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
+
+		for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+		{
+			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
+
+			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
+			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / DepthTest::QUAD_COUNT), 1, 0, 0);
+		}
+
+		vk.cmdEndRenderPass(*m_cmdBuffer);
+		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+	}
+
+	// Create fence
+	{
+		const VkFenceCreateInfo fenceParams =
+		{
+			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,								// const void*			pNext;
+			0u										// VkFenceCreateFlags	flags;
+		};
+
+		m_fence = createFence(vk, vkDevice, &fenceParams);
+	}
+}
+
+DepthTestInstance::~DepthTestInstance (void)
+{
+}
+
+tcu::TestStatus DepthTestInstance::iterate (void)
+{
+	const DeviceInterface&		vk			= m_context.getDeviceInterface();
+	const VkDevice				vkDevice	= m_context.getDevice();
+	const VkQueue				queue		= m_context.getUniversalQueue();
+
+	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+	VK_CHECK(vk.queueSubmit(queue, 1, &m_cmdBuffer.get(), *m_fence));
+	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+	return verifyImage();
+}
+
+tcu::TestStatus DepthTestInstance::verifyImage (void)
+{
+	const tcu::TextureFormat	tcuColorFormat	= mapVkFormat(m_colorFormat);
+	const tcu::TextureFormat	tcuDepthFormat	= mapVkFormat(m_depthFormat);
+	const ColorVertexShader		vertexShader;
+	const ColorFragmentShader	fragmentShader	(tcuColorFormat, tcuDepthFormat);
+	const rr::Program			program			(&vertexShader, &fragmentShader);
+	ReferenceRenderer			refRenderer		(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
+	bool						compareOk		= false;
+
+	// Render reference image
+	{
+		for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+		{
+			// Set depth state
+			rr::RenderState renderState(refRenderer.getViewportState());
+			renderState.fragOps.depthTestEnabled = true;
+			renderState.fragOps.depthFunc = mapVkCompareOp(m_depthCompareOps[quadNdx]);
+
+			refRenderer.draw(renderState,
+							 rr::PRIMITIVETYPE_TRIANGLES,
+							 std::vector<Vertex4RGBA>(m_vertices.begin() + quadNdx * 6,
+													  m_vertices.begin() + (quadNdx + 1) * 6));
+		}
+	}
+
+	// Compare result with reference image
+	{
+		const DeviceInterface&			vk					= m_context.getDeviceInterface();
+		const VkDevice					vkDevice			= m_context.getDevice();
+		const VkQueue					queue				= m_context.getUniversalQueue();
+		const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
+		SimpleAllocator					allocator			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+		de::MovePtr<tcu::TextureLevel>	result				= readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
+
+		compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+															  "IntImageCompare",
+															  "Image comparison",
+															  refRenderer.getAccess(),
+															  result->getAccess(),
+															  tcu::UVec4(2, 2, 2, 2),
+															  tcu::IVec3(1, 1, 0),
+															  true,
+															  tcu::COMPARE_LOG_RESULT);
+	}
+
+	if (compareOk)
+		return tcu::TestStatus::pass("Result image matches reference");
+	else
+		return tcu::TestStatus::fail("Image mismatch");
+}
+
+std::string getFormatCaseName (const VkFormat format)
+{
+	const std::string	fullName	= getFormatName(format);
+
+	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
+
+	return de::toLower(fullName.substr(10));
+}
+
+std::string	getCompareOpsName (const VkCompareOp quadDepthOps[DepthTest::QUAD_COUNT])
+{
+	std::ostringstream name;
+
+	for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+	{
+		const std::string	fullOpName	= getCompareOpName(quadDepthOps[quadNdx]);
+
+		DE_ASSERT(de::beginsWith(fullOpName, "VK_COMPARE_OP_"));
+
+		name << de::toLower(fullOpName.substr(14));
+
+		if (quadNdx < DepthTest::QUAD_COUNT - 1)
+			name << "_";
+	}
+
+	return name.str();
+}
+
+std::string	getCompareOpsDescription (const VkCompareOp quadDepthOps[DepthTest::QUAD_COUNT])
+{
+	std::ostringstream desc;
+	desc << "Draws " << DepthTest::QUAD_COUNT << " quads with depth compare ops: ";
+
+	for (int quadNdx = 0; quadNdx < DepthTest::QUAD_COUNT; quadNdx++)
+	{
+		desc << getCompareOpName(quadDepthOps[quadNdx]) << " at depth " << DepthTest::quadDepths[quadNdx];
+
+		if (quadNdx < DepthTest::QUAD_COUNT - 1)
+			desc << ", ";
+	}
+	return desc.str();
+}
+
+
+} // anonymous
+
+tcu::TestCaseGroup* createDepthTests (tcu::TestContext& testCtx)
+{
+	const VkFormat depthFormats[] =
+	{
+		VK_FORMAT_D16_UNORM,
+		VK_FORMAT_D24_UNORM_X8,
+		VK_FORMAT_D32_SFLOAT,
+		VK_FORMAT_D16_UNORM_S8_UINT,
+		VK_FORMAT_D24_UNORM_S8_UINT,
+		VK_FORMAT_D32_SFLOAT_S8_UINT
+	};
+
+	// Each entry configures the depth compare operators of QUAD_COUNT quads.
+	// All entries cover pair-wise combinations of compare operators.
+	const VkCompareOp depthOps[][DepthTest::QUAD_COUNT] =
+	{
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS,				VK_COMPARE_OP_LESS,				VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS,				VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_LESS,				VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS,				VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS,				VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS,				VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_GREATER,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS,				VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_NOT_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS,				VK_COMPARE_OP_GREATER },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_LESS_EQUAL },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_LESS },
+		{ VK_COMPARE_OP_GREATER_EQUAL,	VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_NEVER },
+		{ VK_COMPARE_OP_LESS,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_EQUAL,			VK_COMPARE_OP_EQUAL },
+		{ VK_COMPARE_OP_NEVER,			VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_ALWAYS,			VK_COMPARE_OP_GREATER_EQUAL },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER,			VK_COMPARE_OP_ALWAYS },
+		{ VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_LESS_EQUAL,		VK_COMPARE_OP_NOT_EQUAL,		VK_COMPARE_OP_GREATER }
+	};
+
+	de::MovePtr<tcu::TestCaseGroup> depthTests (new tcu::TestCaseGroup(testCtx, "depth", "Depth tests"));
+
+	// Tests for format features
+	{
+		de::MovePtr<tcu::TestCaseGroup> formatFeaturesTests (new tcu::TestCaseGroup(testCtx, "format_features", "Checks depth format features"));
+
+		// Formats that must be supported in all implementations
+		addFunctionCase(formatFeaturesTests.get(),
+						"support_d16_unorm",
+						"Tests if VK_FORMAT_D16_UNORM is supported as depth/stencil attachment format",
+						testSupportsDepthStencilFormat,
+						VK_FORMAT_D16_UNORM);
+
+		// Sets where at least one of the formats must be supported
+		const VkFormat	depthOnlyFormats[]		= { VK_FORMAT_D24_UNORM_X8, VK_FORMAT_D32_SFLOAT };
+		const VkFormat	depthStencilFormats[]	= { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT };
+
+		addFunctionCase(formatFeaturesTests.get(),
+						"support_d24_unorm_or_d32_sfloat",
+						"Tests if any of VK_FORMAT_D24_UNORM_X8 or VK_FORMAT_D32_SFLOAT are supported as depth/stencil attachment format",
+						testSupportsAtLeastOneDepthStencilFormat,
+						std::vector<VkFormat>(depthOnlyFormats, depthOnlyFormats + DE_LENGTH_OF_ARRAY(depthOnlyFormats)));
+
+		addFunctionCase(formatFeaturesTests.get(),
+						"support_d24_unorm_s8_uint_or_d32_sfloat_s8_uint",
+						"Tests if any of VK_FORMAT_D24_UNORM_S8_UINT or VK_FORMAT_D32_SFLOAT_S8_UINT are supported as depth/stencil attachment format",
+						testSupportsAtLeastOneDepthStencilFormat,
+						std::vector<VkFormat>(depthStencilFormats, depthStencilFormats + DE_LENGTH_OF_ARRAY(depthStencilFormats)));
+
+		depthTests->addChild(formatFeaturesTests.release());
+	}
+
+	// Tests for format and compare operators
+	{
+		de::MovePtr<tcu::TestCaseGroup> formatTests (new tcu::TestCaseGroup(testCtx, "format", "Uses different depth formats"));
+
+		for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(depthFormats); formatNdx++)
+		{
+			de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
+																					getFormatCaseName(depthFormats[formatNdx]).c_str(),
+																					(std::string("Uses format ") + getFormatName(depthFormats[formatNdx])).c_str()));
+			de::MovePtr<tcu::TestCaseGroup>	compareOpsTests	(new tcu::TestCaseGroup(testCtx, "compare_ops", "Combines depth compare operators"));
+
+			for (size_t opsNdx = 0; opsNdx < DE_LENGTH_OF_ARRAY(depthOps); opsNdx++)
+			{
+				compareOpsTests->addChild(new DepthTest(testCtx,
+														getCompareOpsName(depthOps[opsNdx]),
+														getCompareOpsDescription(depthOps[opsNdx]),
+														depthFormats[formatNdx],
+														depthOps[opsNdx]));
+			}
+			formatTest->addChild(compareOpsTests.release());
+			formatTests->addChild(formatTest.release());
+		}
+		depthTests->addChild(formatTests.release());
+	}
+
+	return depthTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.hpp
new file mode 100644
index 0000000..006ce21
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineDepthTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINEDEPTHTESTS_HPP
+#define _VKTPIPELINEDEPTHTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Depth Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createDepthTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEDEPTHTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.cpp
new file mode 100644
index 0000000..4465822
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.cpp
@@ -0,0 +1,200 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for images.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineImageUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuTextureUtil.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+de::MovePtr<tcu::TextureLevel> readColorAttachment (const vk::DeviceInterface&	vk,
+													vk::VkDevice				device,
+													vk::VkQueue					queue,
+													deUint32					queueFamilyIndex,
+													vk::Allocator&				allocator,
+													vk::VkImage					image,
+													vk::VkFormat				format,
+													const tcu::IVec2&			renderSize)
+{
+	Move<VkBuffer>					buffer;
+	de::MovePtr<Allocation>			bufferAlloc;
+	Move<VkCmdPool>					cmdPool;
+	Move<VkCmdBuffer>				cmdBuffer;
+	Move<VkFence>					fence;
+	const tcu::TextureFormat		tcuFormat		= mapVkFormat(format);
+	const VkDeviceSize				pixelDataSize	= renderSize.x() * renderSize.y() * tcuFormat.getPixelSize();
+	de::MovePtr<tcu::TextureLevel>	resultLevel		(new tcu::TextureLevel(tcuFormat, renderSize.x(), renderSize.y()));
+
+	// Create destination buffer
+	{
+		const VkBufferCreateInfo bufferParams =
+		{
+			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			pixelDataSize,								// VkDeviceSize			size;
+			VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,   // VkBufferUsageFlags	usage;
+			0u,											// VkBufferCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
+			0u,											// deUint32				queueFamilyCount;
+			DE_NULL,									// const deUint32*		pQueueFamilyIndices;
+		};
+
+		buffer		= createBuffer(vk, device, &bufferParams);
+		bufferAlloc = allocator.allocate(getBufferMemoryRequirements(vk, device, *buffer), MemoryRequirement::HostVisible);
+		VK_CHECK(vk.bindBufferMemory(device, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
+	}
+
+	// Create command pool and buffer
+	{
+		const VkCmdPoolCreateInfo cmdPoolParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			queueFamilyIndex,							// deUint32				queueFamilyIndex;
+			VK_CMD_POOL_CREATE_TRANSIENT_BIT			// VkCmdPoolCreateFlags	flags;
+		};
+
+		cmdPool = createCommandPool(vk, device, &cmdPoolParams);
+
+		const VkCmdBufferCreateInfo cmdBufferParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			*cmdPool,									// VkCmdPool				cmdPool;
+			VK_CMD_BUFFER_LEVEL_PRIMARY,				// VkCmdBufferLevel			level;
+			0u,											// VkCmdBufferCreateFlags	flags;
+		};
+
+		cmdBuffer = createCommandBuffer(vk, device, &cmdBufferParams);
+	}
+
+	// Create fence
+	{
+		const VkFenceCreateInfo fenceParams =
+		{
+			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			0u											// VkFenceCreateFlags	flags;
+		};
+
+		fence = createFence(vk, device, &fenceParams);
+	}
+
+	// Barriers for copying image to buffer
+
+	const VkImageMemoryBarrier imageBarrier =
+	{
+		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
+		DE_NULL,									// const void*				pNext;
+		VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,		// VkMemoryOutputFlags		outputMask;
+		VK_MEMORY_INPUT_TRANSFER_BIT,				// VkMemoryInputFlags		inputMask;
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			oldLayout;
+		VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,	// VkImageLayout			newLayout;
+		VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
+		VK_QUEUE_FAMILY_IGNORED,					// deUint32					destQueueFamilyIndex;
+		image,										// VkImage					image;
+		{											// VkImageSubresourceRange	subresourceRange;
+			VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags	aspectMask;
+			0u,							// deUint32				baseMipLevel;
+			1u,							// deUint32				mipLevels;
+			0u,							// deUint32				baseArraySlice;
+			1u							// deUint32				arraySize;
+		}
+	};
+
+	const VkBufferMemoryBarrier bufferBarrier =
+	{
+		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType		sType;
+		DE_NULL,									// const void*			pNext;
+		VK_MEMORY_OUTPUT_TRANSFER_BIT,				// VkMemoryOutputFlags	outputMask;
+		VK_MEMORY_INPUT_HOST_READ_BIT,				// VkMemoryInputFlags	inputMask;
+		VK_QUEUE_FAMILY_IGNORED,					// deUint32				srcQueueFamilyIndex;
+		VK_QUEUE_FAMILY_IGNORED,					// deUint32				destQueueFamilyIndex;
+		*buffer,									// VkBuffer				buffer;
+		0u,											// VkDeviceSize			offset;
+		pixelDataSize								// VkDeviceSize			size;
+	};
+
+	const VkCmdBufferBeginInfo cmdBufferBeginInfo =
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,												// VkStructureType			sType;
+		DE_NULL,																				// const void*				pNext;
+		VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// VkCmdBufferOptimizeFlags	flags;
+		DE_NULL,																				// VkRenderPass				renderPass;
+		0u,																						// deUint32					subpass;
+		DE_NULL																					// VkFramebuffer			framebuffer;
+	};
+
+	const void* const	imageBarrierPtr		= &imageBarrier;
+	const void* const	bufferBarrierPtr	= &bufferBarrier;
+
+	// Copy image to buffer
+
+	const VkBufferImageCopy copyRegion =
+	{
+		0u,											// VkDeviceSize				bufferOffset;
+		(deUint32)renderSize.x(),					// deUint32					bufferRowLength;
+		(deUint32)renderSize.y(),					// deUint32					bufferImageHeight;
+		{ VK_IMAGE_ASPECT_COLOR, 0u, 0u, 1u },		// VkImageSubresourceCopy	imageSubresource;
+		{ 0, 0, 0 },								// VkOffset3D				imageOffset;
+		{ renderSize.x(), renderSize.y(), 1 }		// VkExtent3D				imageExtent;
+	};
+
+	VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
+	vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_FALSE, 1, &imageBarrierPtr);
+	vk.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, *buffer, 1, &copyRegion);
+	vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_FALSE, 1, &bufferBarrierPtr);
+	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+
+	VK_CHECK(vk.queueSubmit(queue, 1, &cmdBuffer.get(), *fence));
+	VK_CHECK(vk.waitForFences(device, 1, &fence.get(), 0, ~(0ull) /* infinity */));
+
+	// Read buffer data
+	invalidateMappedMemoryRange(vk, device, bufferAlloc->getMemory(), bufferAlloc->getOffset(), pixelDataSize);
+	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), bufferAlloc->getHostPtr()));
+
+	return resultLevel;
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.hpp
new file mode 100644
index 0000000..b3e91aa
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineImageUtil.hpp
@@ -0,0 +1,70 @@
+#ifndef _VKTPIPELINEIMAGEUTIL_HPP
+#define _VKTPIPELINEIMAGEUTIL_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for images.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "vkDefs.hpp"
+#include "vkDefs.hpp"
+#include "vkPlatform.hpp"
+#include "vkMemUtil.hpp"
+#include "vkRef.hpp"
+#include "tcuTexture.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+/*--------------------------------------------------------------------*//*!
+ * Gets a tcu::TextureLevel initialized with data from a VK color
+ * attachment.
+ *
+ * The VkImage must be non-multisampled and able to be used as a source
+ * operand for transfer operations.
+ *//*--------------------------------------------------------------------*/
+de::MovePtr<tcu::TextureLevel> readColorAttachment (const vk::DeviceInterface&	vk,
+													vk::VkDevice				device,
+													vk::VkQueue					queue,
+													deUint32					queueFamilyIndex,
+													vk::Allocator&				allocator,
+													vk::VkImage					image,
+													vk::VkFormat				format,
+													const tcu::IVec2&			renderSize);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEIMAGEUTIL_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.cpp
new file mode 100644
index 0000000..b9ebe7d
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.cpp
@@ -0,0 +1,287 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Reference renderer.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "rrShadingContext.hpp"
+#include "rrVertexAttrib.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+rr::BlendFunc mapVkBlend (VkBlend blend)
+{
+	switch (blend)
+	{
+		case VK_BLEND_ZERO: 					return rr::BLENDFUNC_ZERO;
+		case VK_BLEND_ONE:						return rr::BLENDFUNC_ONE;
+		case VK_BLEND_SRC_COLOR:				return rr::BLENDFUNC_SRC_COLOR;
+		case VK_BLEND_ONE_MINUS_SRC_COLOR:		return rr::BLENDFUNC_ONE_MINUS_SRC_COLOR;
+		case VK_BLEND_DEST_COLOR:				return rr::BLENDFUNC_DST_COLOR;
+		case VK_BLEND_ONE_MINUS_DEST_COLOR:		return rr::BLENDFUNC_ONE_MINUS_DST_COLOR;
+		case VK_BLEND_SRC_ALPHA:				return rr::BLENDFUNC_SRC_ALPHA;
+		case VK_BLEND_ONE_MINUS_SRC_ALPHA:		return rr::BLENDFUNC_ONE_MINUS_SRC_ALPHA;
+		case VK_BLEND_DEST_ALPHA:				return rr::BLENDFUNC_DST_ALPHA;
+		case VK_BLEND_ONE_MINUS_DEST_ALPHA:		return rr::BLENDFUNC_ONE_MINUS_DST_ALPHA;
+		case VK_BLEND_CONSTANT_COLOR:			return rr::BLENDFUNC_CONSTANT_COLOR;
+		case VK_BLEND_ONE_MINUS_CONSTANT_COLOR:	return rr::BLENDFUNC_ONE_MINUS_CONSTANT_COLOR;
+		case VK_BLEND_CONSTANT_ALPHA:			return rr::BLENDFUNC_CONSTANT_ALPHA;
+		case VK_BLEND_ONE_MINUS_CONSTANT_ALPHA:	return rr::BLENDFUNC_ONE_MINUS_CONSTANT_ALPHA;
+		case VK_BLEND_SRC_ALPHA_SATURATE:		return rr::BLENDFUNC_SRC_ALPHA_SATURATE;
+		case VK_BLEND_SRC1_COLOR:				return rr::BLENDFUNC_SRC1_COLOR;
+		case VK_BLEND_ONE_MINUS_SRC1_COLOR:		return rr::BLENDFUNC_ONE_MINUS_SRC1_COLOR;
+		case VK_BLEND_SRC1_ALPHA:				return rr::BLENDFUNC_SRC1_ALPHA;
+		case VK_BLEND_ONE_MINUS_SRC1_ALPHA:		return rr::BLENDFUNC_ONE_MINUS_SRC1_ALPHA;
+		default:
+			DE_ASSERT(false);
+	}
+	return rr::BLENDFUNC_LAST;
+}
+
+rr::BlendEquation mapVkBlendOp (VkBlendOp blendOp)
+{
+	switch (blendOp)
+	{
+		case VK_BLEND_OP_ADD:					return rr::BLENDEQUATION_ADD;
+		case VK_BLEND_OP_SUBTRACT:				return rr::BLENDEQUATION_SUBTRACT;
+		case VK_BLEND_OP_REVERSE_SUBTRACT:		return rr::BLENDEQUATION_REVERSE_SUBTRACT;
+		case VK_BLEND_OP_MIN:					return rr::BLENDEQUATION_MIN;
+		case VK_BLEND_OP_MAX:					return rr::BLENDEQUATION_MAX;
+		default:
+			DE_ASSERT(false);
+	}
+	return rr::BLENDEQUATION_LAST;
+}
+
+tcu::BVec4 mapVkChannelFlags (VkChannelFlags flags)
+{
+	return tcu::BVec4(flags & VK_CHANNEL_R_BIT,
+					  flags & VK_CHANNEL_G_BIT,
+					  flags & VK_CHANNEL_B_BIT,
+					  flags & VK_CHANNEL_A_BIT);
+}
+
+rr::TestFunc mapVkCompareOp (VkCompareOp compareFunc)
+{
+	switch (compareFunc)
+	{
+		case VK_COMPARE_OP_NEVER:			return rr::TESTFUNC_NEVER;
+		case VK_COMPARE_OP_LESS:			return rr::TESTFUNC_LESS;
+		case VK_COMPARE_OP_EQUAL:			return rr::TESTFUNC_EQUAL;
+		case VK_COMPARE_OP_LESS_EQUAL:		return rr::TESTFUNC_LEQUAL;
+		case VK_COMPARE_OP_GREATER:			return rr::TESTFUNC_GREATER;
+		case VK_COMPARE_OP_NOT_EQUAL:		return rr::TESTFUNC_NOTEQUAL;
+		case VK_COMPARE_OP_GREATER_EQUAL:	return rr::TESTFUNC_GEQUAL;
+		case VK_COMPARE_OP_ALWAYS:			return rr::TESTFUNC_ALWAYS;
+		default:
+			DE_ASSERT(false);
+	}
+	return rr::TESTFUNC_LAST;
+}
+
+rr::PrimitiveType mapVkPrimitiveTopology (VkPrimitiveTopology primitiveTopology)
+{
+	switch (primitiveTopology)
+	{
+		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:				return rr::PRIMITIVETYPE_POINTS;
+		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:				return rr::PRIMITIVETYPE_LINES;
+		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:				return rr::PRIMITIVETYPE_LINE_STRIP;
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:			return rr::PRIMITIVETYPE_TRIANGLES;
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:			return rr::PRIMITIVETYPE_TRIANGLE_FAN;
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:			return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
+		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ:			return rr::PRIMITIVETYPE_LINES_ADJACENCY;
+		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ:			return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ:		return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
+		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ:		return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
+		default:
+			DE_ASSERT(false);
+	}
+	return rr::PRIMITIVETYPE_LAST;
+}
+
+rr::StencilOp mapVkStencilOp (vk::VkStencilOp stencilOp)
+{
+	switch (stencilOp)
+	{
+		case VK_STENCIL_OP_KEEP:		return rr::STENCILOP_KEEP;
+		case VK_STENCIL_OP_ZERO:		return rr::STENCILOP_ZERO;
+		case VK_STENCIL_OP_REPLACE:		return rr::STENCILOP_REPLACE;
+		case VK_STENCIL_OP_INC_CLAMP:	return rr::STENCILOP_INCR;
+		case VK_STENCIL_OP_DEC_CLAMP:	return rr::STENCILOP_DECR;
+		case VK_STENCIL_OP_INVERT:		return rr::STENCILOP_INVERT;
+		case VK_STENCIL_OP_INC_WRAP:	return rr::STENCILOP_INCR_WRAP;
+		case VK_STENCIL_OP_DEC_WRAP:	return rr::STENCILOP_DECR_WRAP;
+		default:
+			DE_ASSERT(false);
+	}
+	return rr::STENCILOP_LAST;
+}
+
+ReferenceRenderer::ReferenceRenderer(int						surfaceWidth,
+									 int						surfaceHeight,
+									 int						numSamples,
+									 const tcu::TextureFormat&	colorFormat,
+									 const tcu::TextureFormat&	depthStencilFormat,
+									 const rr::Program* const	program)
+	: m_surfaceWidth		(surfaceWidth)
+	, m_surfaceHeight		(surfaceHeight)
+	, m_numSamples			(numSamples)
+	, m_colorFormat			(colorFormat)
+	, m_depthStencilFormat	(depthStencilFormat)
+	, m_program				(program)
+{
+	const tcu::TextureChannelClass	formatClass				= tcu::getTextureChannelClass(colorFormat.type);
+	const bool						hasDepthStencil			= (m_depthStencilFormat.order != tcu::TextureFormat::CHANNELORDER_LAST);
+	const bool						hasDepthBufferOnly		= (m_depthStencilFormat.order == tcu::TextureFormat::D);
+	const bool						hasStencilBufferOnly	= (m_depthStencilFormat.order == tcu::TextureFormat::S);
+	const int						actualSamples			= (formatClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || formatClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)? 1: m_numSamples;
+
+	m_colorBuffer.setStorage(m_colorFormat, actualSamples, m_surfaceWidth, m_surfaceHeight);
+	m_resolveColorBuffer.setStorage(m_colorFormat, m_surfaceWidth, m_surfaceHeight);
+
+	if (formatClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
+	{
+		tcu::clear(m_colorBuffer.getAccess(), defaultClearColorInt(m_colorFormat));
+		tcu::clear(m_resolveColorBuffer.getAccess(), defaultClearColorInt(m_colorFormat));
+	}
+	else if (formatClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
+	{
+		tcu::clear(m_colorBuffer.getAccess(), defaultClearColorUint(m_colorFormat));
+		tcu::clear(m_resolveColorBuffer.getAccess(), defaultClearColorUint(m_colorFormat));
+	}
+	else
+	{
+		tcu::Vec4 clearColor = defaultClearColor(m_colorFormat);
+
+		if (isSRGB(m_colorFormat))
+			clearColor = tcu::linearToSRGB(clearColor);
+
+		tcu::clear(m_colorBuffer.getAccess(), clearColor);
+		tcu::clear(m_resolveColorBuffer.getAccess(), clearColor);
+	}
+
+	if (hasDepthStencil)
+	{
+		if (hasDepthBufferOnly)
+		{
+			m_depthStencilBuffer.setStorage(m_depthStencilFormat, actualSamples, surfaceWidth, surfaceHeight);
+			tcu::clearDepth(m_depthStencilBuffer.getAccess(), defaultClearDepth());
+
+			m_renderTarget = new rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_colorBuffer.getAccess()),
+												  rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_depthStencilBuffer.getAccess()));
+		}
+		else if (hasStencilBufferOnly)
+		{
+			m_depthStencilBuffer.setStorage(m_depthStencilFormat, actualSamples, surfaceWidth, surfaceHeight);
+			tcu::clearStencil(m_depthStencilBuffer.getAccess(), defaultClearStencil());
+
+			m_renderTarget = new rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_colorBuffer.getAccess()),
+												  rr::MultisamplePixelBufferAccess(),
+												  rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_depthStencilBuffer.getAccess()));
+		}
+		else
+		{
+			m_depthStencilBuffer.setStorage(m_depthStencilFormat, actualSamples, surfaceWidth, surfaceHeight);
+
+			tcu::clearDepth(m_depthStencilBuffer.getAccess(), defaultClearDepth());
+			tcu::clearStencil(m_depthStencilBuffer.getAccess(), defaultClearStencil());
+
+			m_renderTarget = new rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_colorBuffer.getAccess()),
+												  rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_depthStencilBuffer.getAccess()),
+												  rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_depthStencilBuffer.getAccess()));
+		}
+	}
+	else
+	{
+		m_renderTarget = new rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(m_colorBuffer.getAccess()));
+	}
+}
+
+ReferenceRenderer::~ReferenceRenderer (void)
+{
+	delete m_renderTarget;
+}
+
+void ReferenceRenderer::draw (const rr::RenderState&			renderState,
+							  const rr::PrimitiveType			primitive,
+							  const std::vector<Vertex4RGBA>&	vertexBuffer)
+{
+	const rr::PrimitiveList primitives(primitive, (int)vertexBuffer.size(), 0);
+
+	std::vector<tcu::Vec4> positions;
+	std::vector<tcu::Vec4> colors;
+
+	for (size_t vertexNdx = 0; vertexNdx < vertexBuffer.size(); vertexNdx++)
+	{
+		const Vertex4RGBA& v = vertexBuffer[vertexNdx];
+		positions.push_back(v.position);
+		colors.push_back(v.color);
+	}
+
+	rr::VertexAttrib vertexAttribs[2];
+
+	// Position attribute
+	vertexAttribs[0].type		= rr::VERTEXATTRIBTYPE_FLOAT;
+	vertexAttribs[0].size		= 4;
+	vertexAttribs[0].pointer	= positions.data();
+	// UV attribute
+	vertexAttribs[1].type		= rr::VERTEXATTRIBTYPE_FLOAT;
+	vertexAttribs[1].size		= 4;
+	vertexAttribs[1].pointer	= colors.data();
+
+	rr::DrawCommand drawQuadCommand(renderState, *m_renderTarget, *m_program, 2, vertexAttribs, primitives);
+
+	m_renderer.draw(drawQuadCommand);
+}
+
+tcu::PixelBufferAccess ReferenceRenderer::getAccess (void)
+{
+	rr::MultisampleConstPixelBufferAccess multiSampleAccess = rr::MultisampleConstPixelBufferAccess::fromMultisampleAccess(m_colorBuffer.getAccess());
+	rr::resolveMultisampleColorBuffer(m_resolveColorBuffer.getAccess(), multiSampleAccess);
+
+	return m_resolveColorBuffer.getAccess();
+}
+
+const rr::ViewportState ReferenceRenderer::getViewportState (void) const
+{
+	return rr::ViewportState(rr::WindowRectangle(0, 0, m_surfaceWidth, m_surfaceHeight));
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.hpp
new file mode 100644
index 0000000..761978c
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineReferenceRenderer.hpp
@@ -0,0 +1,185 @@
+#ifndef _VKTPIPELINEREFERENCERENDERER_HPP
+#define _VKTPIPELINEREFERENCERENDERER_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Reference renderer.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "tcuVector.hpp"
+#include "tcuVectorType.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTextureUtil.hpp"
+#include "rrRenderState.hpp"
+#include "rrRenderer.hpp"
+#include <cstring>
+
+namespace vkt
+{
+
+namespace pipeline
+{
+
+class ColorVertexShader : public rr::VertexShader
+{
+public:
+	ColorVertexShader (void) : rr::VertexShader(2, 2)
+	{
+		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
+		m_inputs[1].type	= rr::GENERICVECTYPE_FLOAT;
+
+		m_outputs[0].type	= rr::GENERICVECTYPE_FLOAT;
+		m_outputs[1].type	= rr::GENERICVECTYPE_FLOAT;
+	}
+
+	virtual ~ColorVertexShader (void) {}
+
+	virtual void shadeVertices (const rr::VertexAttrib*		inputs,
+								rr::VertexPacket* const*	packets,
+								const int					numPackets) const
+	{
+		tcu::Vec4 position;
+		tcu::Vec4 color;
+
+		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
+		{
+			rr::VertexPacket* const packet	= packets[packetNdx];
+
+			readVertexAttrib(position, inputs[0], packet->instanceNdx, packet->vertexNdx);
+			readVertexAttrib(color, inputs[1], packet->instanceNdx, packet->vertexNdx);
+
+			packet->outputs[0]	= position;
+			packet->outputs[1]	= color;
+			packet->position	= position;
+		}
+	}
+};
+
+class ColorFragmentShader : public rr::FragmentShader
+{
+private:
+	const tcu::TextureFormat		m_colorFormat;
+	const tcu::TextureFormat		m_depthStencilFormat;
+
+public:
+	ColorFragmentShader (const tcu::TextureFormat& colorFormat,
+						 const tcu::TextureFormat& depthStencilFormat)
+		: rr::FragmentShader	(2, 1)
+		, m_colorFormat			(colorFormat)
+		, m_depthStencilFormat	(depthStencilFormat)
+	{
+		const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(m_colorFormat.type);
+
+		m_inputs[0].type	= rr::GENERICVECTYPE_FLOAT;
+		m_inputs[1].type	= rr::GENERICVECTYPE_FLOAT;
+		m_outputs[0].type	= (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)? rr::GENERICVECTYPE_INT32 :
+							  (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)? rr::GENERICVECTYPE_UINT32
+							  : rr::GENERICVECTYPE_FLOAT;
+	}
+
+	virtual ~ColorFragmentShader (void) {}
+
+	virtual void shadeFragments (rr::FragmentPacket*				packets,
+								 const int							numPackets,
+								 const rr::FragmentShadingContext&	context) const
+	{
+		for (int packetNdx = 0; packetNdx < numPackets; packetNdx++)
+		{
+			const rr::FragmentPacket& packet = packets[packetNdx];
+
+			if (m_depthStencilFormat.order == tcu::TextureFormat::D || m_depthStencilFormat.order == tcu::TextureFormat::DS)
+			{
+				for (int fragNdx = 0; fragNdx < 4; fragNdx++)
+				{
+					const tcu::Vec4 vtxPosition = rr::readVarying<float>(packet, context, 0, fragNdx);
+					rr::writeFragmentDepth(context, packetNdx, fragNdx, 0, vtxPosition.z());
+				}
+			}
+
+			for (int fragNdx = 0; fragNdx < 4; fragNdx++)
+			{
+				const tcu::Vec4 vtxColor = rr::readVarying<float>(packet, context, 1, fragNdx);
+				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, vtxColor);
+			}
+		}
+	}
+};
+
+class ReferenceRenderer
+{
+public:
+								ReferenceRenderer		(int							surfaceWidth,
+														 int							surfaceHeight,
+														 int							numSamples,
+														 const tcu::TextureFormat&		colorFormat,
+														 const tcu::TextureFormat&		depthStencilFormat,
+														 const rr::Program* const		program);
+
+	virtual						~ReferenceRenderer		(void);
+
+	void						draw					(const rr::RenderState&				renderState,
+														 const rr::PrimitiveType			primitive,
+														 const std::vector<Vertex4RGBA>&	vertexBuffer);
+	tcu::PixelBufferAccess		getAccess				(void);
+	const rr::ViewportState		getViewportState		(void) const;
+
+private:
+	rr::Renderer				m_renderer;
+
+	const int					m_surfaceWidth;
+	const int					m_surfaceHeight;
+	const int					m_numSamples;
+
+	const tcu::TextureFormat	m_colorFormat;
+	const tcu::TextureFormat	m_depthStencilFormat;
+
+	tcu::TextureLevel			m_colorBuffer;
+	tcu::TextureLevel			m_resolveColorBuffer;
+	tcu::TextureLevel			m_depthStencilBuffer;
+
+	rr::RenderTarget*			m_renderTarget;
+	const rr::Program*			m_program;
+};
+
+rr::BlendFunc					mapVkBlend				(vk::VkBlend blend);
+rr::BlendEquation				mapVkBlendOp			(vk::VkBlendOp blendOp);
+tcu::BVec4						mapVkChannelFlags		(vk::VkChannelFlags flags);
+rr::TestFunc					mapVkCompareOp			(vk::VkCompareOp compareFunc);
+rr::PrimitiveType				mapVkPrimitiveTopology	(vk::VkPrimitiveTopology primitiveTopology);
+rr::StencilOp					mapVkStencilOp			(vk::VkStencilOp stencilOp);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEREFERENCERENDERER_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.cpp
new file mode 100644
index 0000000..a527ecf
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.cpp
@@ -0,0 +1,1158 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Stencil Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineStencilTests.hpp"
+#include "vktPipelineClearUtil.hpp"
+#include "vktPipelineImageUtil.hpp"
+#include "vktPipelineVertexUtil.hpp"
+#include "vktPipelineReferenceRenderer.hpp"
+#include "vktPipelineUniqueRandomIterator.hpp"
+#include "vktTestCase.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "deMemory.h"
+#include "deRandom.hpp"
+#include "deStringUtil.hpp"
+#include "deUniquePtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+using namespace vk;
+
+namespace
+{
+
+bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
+{
+	VkFormatProperties formatProps;
+
+	VK_CHECK(instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps));
+
+	return formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+}
+
+class StencilOpStateUniqueRandomIterator : public UniqueRandomIterator<VkStencilOpState>
+{
+public:
+								StencilOpStateUniqueRandomIterator	(int seed);
+	virtual						~StencilOpStateUniqueRandomIterator	(void) {}
+	virtual VkStencilOpState	getIndexedValue (deUint32 index);
+
+private:
+	const static VkStencilOp	m_stencilOps[];
+	const static VkCompareOp	m_compareOps[];
+
+	// Pre-calculated constants
+	const static deUint32		m_stencilOpsLength;
+	const static deUint32		m_stencilOpsLength2;
+	const static deUint32		m_stencilOpsLength3;
+	const static deUint32		m_compareOpsLength;
+
+	// Total number of cross-combinations of (stencilFailOp x stencilPassOp x stencilDepthFailOp x stencilCompareOp)
+	const static deUint32		m_totalStencilOpStates;
+};
+
+
+class StencilTest : public vkt::TestCase
+{
+public:
+	enum
+	{
+		QUAD_COUNT = 4
+	};
+
+	struct StencilStateConfig
+	{
+		deUint32	frontReadMask;
+		deUint32	frontWriteMask;
+		deUint32	frontRef;
+
+		deUint32	backReadMask;
+		deUint32	backWriteMask;
+		deUint32	backRef;
+	};
+
+	const static StencilStateConfig			s_stencilStateConfigs[QUAD_COUNT];
+	const static float						s_quadDepths[QUAD_COUNT];
+
+
+											StencilTest				(tcu::TestContext&			testContext,
+																	 const std::string&			name,
+																	 const std::string&			description,
+																	 VkFormat					stencilFormat,
+																	 const VkStencilOpState&	stencilOpStateFront,
+																	 const VkStencilOpState&	stencilOpStateBack);
+	virtual									~StencilTest			(void);
+	virtual void							initPrograms			(SourceCollections& sourceCollections) const;
+	virtual TestInstance*					createInstance			(Context& context) const;
+
+private:
+	VkFormat								m_stencilFormat;
+	const VkStencilOpState					m_stencilOpStateFront;
+	const VkStencilOpState					m_stencilOpStateBack;
+};
+
+class StencilTestInstance : public vkt::TestInstance
+{
+public:
+										StencilTestInstance		(Context&					context,
+																 VkFormat					stencilFormat,
+																 const VkStencilOpState&	stencilOpStatesFront,
+																 const VkStencilOpState&	stencilOpStatesBack);
+	virtual								~StencilTestInstance	(void);
+	virtual tcu::TestStatus				iterate					(void);
+
+private:
+	tcu::TestStatus						verifyImage				(void);
+
+	VkStencilOpState					m_stencilOpStateFront;
+	VkStencilOpState					m_stencilOpStateBack;
+	const tcu::IVec2					m_renderSize;
+	const VkFormat						m_colorFormat;
+	const VkFormat						m_stencilFormat;
+
+	VkImageCreateInfo					m_colorImageCreateInfo;
+	Move<VkImage>						m_colorImage;
+	de::MovePtr<Allocation>				m_colorImageAlloc;
+	Move<VkImage>						m_stencilImage;
+	de::MovePtr<Allocation>				m_stencilImageAlloc;
+	Move<VkImageView>					m_colorAttachmentView;
+	Move<VkImageView>					m_stencilAttachmentView;
+	Move<VkRenderPass>					m_renderPass;
+	Move<VkFramebuffer>					m_framebuffer;
+
+	Move<VkShaderModule>				m_vertexShaderModule;
+	Move<VkShaderModule>				m_fragmentShaderModule;
+	Move<VkShader>						m_vertexShader;
+	Move<VkShader>						m_fragmentShader;
+
+	Move<VkBuffer>						m_vertexBuffer;
+	std::vector<Vertex4RGBA>			m_vertices;
+	de::MovePtr<Allocation>				m_vertexBufferAlloc;
+
+	Move<VkPipelineLayout>				m_pipelineLayout;
+	Move<VkPipeline>					m_graphicsPipelines[StencilTest::QUAD_COUNT];
+
+	Move<VkCmdPool>						m_cmdPool;
+	Move<VkCmdBuffer>					m_cmdBuffer;
+
+	Move<VkFence>						m_fence;
+};
+
+
+// StencilOpStateUniqueRandomIterator
+
+const VkStencilOp StencilOpStateUniqueRandomIterator::m_stencilOps[] =
+{
+	VK_STENCIL_OP_KEEP,
+	VK_STENCIL_OP_ZERO,
+	VK_STENCIL_OP_REPLACE,
+	VK_STENCIL_OP_INC_CLAMP,
+	VK_STENCIL_OP_DEC_CLAMP,
+	VK_STENCIL_OP_INVERT,
+	VK_STENCIL_OP_INC_WRAP,
+	VK_STENCIL_OP_DEC_WRAP
+};
+
+const VkCompareOp StencilOpStateUniqueRandomIterator::m_compareOps[] =
+{
+	VK_COMPARE_OP_NEVER,
+	VK_COMPARE_OP_LESS,
+	VK_COMPARE_OP_EQUAL,
+	VK_COMPARE_OP_LESS_EQUAL,
+	VK_COMPARE_OP_GREATER,
+	VK_COMPARE_OP_NOT_EQUAL,
+	VK_COMPARE_OP_GREATER_EQUAL,
+	VK_COMPARE_OP_ALWAYS
+};
+
+const deUint32 StencilOpStateUniqueRandomIterator::m_stencilOpsLength		= DE_LENGTH_OF_ARRAY(m_stencilOps);
+const deUint32 StencilOpStateUniqueRandomIterator::m_stencilOpsLength2		= m_stencilOpsLength * m_stencilOpsLength;
+const deUint32 StencilOpStateUniqueRandomIterator::m_stencilOpsLength3		= m_stencilOpsLength2 * m_stencilOpsLength;
+const deUint32 StencilOpStateUniqueRandomIterator::m_compareOpsLength		= DE_LENGTH_OF_ARRAY(m_compareOps);
+const deUint32 StencilOpStateUniqueRandomIterator::m_totalStencilOpStates	= m_stencilOpsLength3 * m_compareOpsLength;
+
+StencilOpStateUniqueRandomIterator::StencilOpStateUniqueRandomIterator (int seed)
+	: UniqueRandomIterator<VkStencilOpState>(m_totalStencilOpStates, m_totalStencilOpStates, seed)
+{
+}
+
+VkStencilOpState StencilOpStateUniqueRandomIterator::getIndexedValue (deUint32 index)
+{
+	const deUint32 stencilCompareOpIndex = index / m_stencilOpsLength3;
+	const deUint32 stencilCompareOpSeqIndex = stencilCompareOpIndex * m_stencilOpsLength3;
+
+	const deUint32 stencilDepthFailOpIndex = (index - stencilCompareOpSeqIndex) / m_stencilOpsLength2;
+	const deUint32 stencilDepthFailOpSeqIndex = stencilDepthFailOpIndex * m_stencilOpsLength2;
+
+	const deUint32 stencilPassOpIndex = (index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex) / m_stencilOpsLength;
+	const deUint32 stencilPassOpSeqIndex = stencilPassOpIndex * m_stencilOpsLength;
+
+	const deUint32 stencilFailOpIndex = index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex - stencilPassOpSeqIndex;
+
+	const VkStencilOpState stencilOpState =
+	{
+		m_stencilOps[stencilFailOpIndex],		// VkStencilOp	stencilFailOp;
+		m_stencilOps[stencilPassOpIndex],		// VkStencilOp	stencilPassOp;
+		m_stencilOps[stencilDepthFailOpIndex],	// VkStencilOp	stencilDepthFailOp;
+		m_compareOps[stencilCompareOpIndex],	// VkCompareOp	stencilCompareOp;
+		0x0,									// deUint32		stencilCompareMask;
+		0x0,									// deUint32		stencilWriteMask;
+		0x0										// deUint32		stencilReference;
+	};
+
+	return stencilOpState;
+}
+
+
+// StencilTest
+
+const StencilTest::StencilStateConfig StencilTest::s_stencilStateConfigs[QUAD_COUNT] =
+{
+	//	frontReadMask	frontWriteMask		frontRef		backReadMask	backWriteMask	backRef
+	{	0xFF,			0xFF,				0xAB,			0xF0,			0xFF,			0xFF	},
+	{	0xFF,			0xF0,				0xCD,			0xF0,			0xF0,			0xEF	},
+	{	0xF0,			0x0F,				0xEF,			0xFF,			0x0F,			0xCD	},
+	{	0xF0,			0x01,				0xFF,			0xFF,			0x01,			0xAB	}
+};
+
+const float StencilTest::s_quadDepths[QUAD_COUNT] =
+{
+	0.1f,
+	0.0f,
+	0.3f,
+	0.2f
+};
+
+StencilTest::StencilTest (tcu::TestContext&			testContext,
+						  const std::string&		name,
+						  const std::string&		description,
+						  VkFormat					stencilFormat,
+						  const VkStencilOpState&	stencilOpStateFront,
+						  const VkStencilOpState&	stencilOpStateBack)
+	: vkt::TestCase			(testContext, name, description)
+	, m_stencilFormat		(stencilFormat)
+	, m_stencilOpStateFront	(stencilOpStateFront)
+	, m_stencilOpStateBack	(stencilOpStateBack)
+{
+}
+
+StencilTest::~StencilTest (void)
+{
+}
+
+TestInstance* StencilTest::createInstance (Context& context) const
+{
+	return new StencilTestInstance(context, m_stencilFormat, m_stencilOpStateFront, m_stencilOpStateBack);
+}
+
+void StencilTest::initPrograms (SourceCollections& sourceCollections) const
+{
+	sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
+		"#version 310 es\n"
+		"layout(location = 0) in vec4 position;\n"
+		"layout(location = 1) in vec4 color;\n"
+		"layout(location = 0) out highp vec4 vtxColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	gl_Position = position;\n"
+		"	vtxColor = color;\n"
+		"}\n");
+
+	sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
+		"#version 310 es\n"
+		"layout(location = 0) in highp vec4 vtxColor;\n"
+		"layout(location = 0) out highp vec4 fragColor;\n"
+		"void main (void)\n"
+		"{\n"
+		"	fragColor = vtxColor;\n"
+		"}\n");
+}
+
+
+// StencilTestInstance
+
+StencilTestInstance::StencilTestInstance (Context&					context,
+										  VkFormat					stencilFormat,
+										  const VkStencilOpState&	stencilOpStateFront,
+										  const VkStencilOpState&	stencilOpStateBack)
+	: vkt::TestInstance		(context)
+	, m_stencilOpStateFront	(stencilOpStateFront)
+	, m_stencilOpStateBack	(stencilOpStateBack)
+	, m_renderSize			(32, 32)
+	, m_colorFormat			(VK_FORMAT_R8G8B8A8_UNORM)
+	, m_stencilFormat		(stencilFormat)
+{
+	const DeviceInterface&		vk					= context.getDeviceInterface();
+	const VkDevice				vkDevice			= context.getDevice();
+	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+	SimpleAllocator				memAlloc			(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
+	const VkChannelMapping		channelMappingRGBA	= { VK_CHANNEL_SWIZZLE_R, VK_CHANNEL_SWIZZLE_G, VK_CHANNEL_SWIZZLE_B, VK_CHANNEL_SWIZZLE_A };
+
+	// Create color image
+	{
+		const VkImageCreateInfo colorImageParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType		sType;
+			DE_NULL,																	// const void*			pNext;
+			VK_IMAGE_TYPE_2D,															// VkImageType			imageType;
+			m_colorFormat,																// VkFormat				format;
+			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D			extent;
+			1u,																			// deUint32				mipLevels;
+			1u,																			// deUint32				arraySize;
+			1u,																			// deUint32				samples;
+			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling		tiling;
+			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	// VkImageUsageFlags	usage;
+			0u,																			// VkImageCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode		sharingMode;
+			1u,																			// deUint32				queueFamilyCount;
+			&queueFamilyIndex,															// const deUint32*		pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout		initialLayout;
+		};
+
+		m_colorImageCreateInfo	= colorImageParams;
+		m_colorImage			= createImage(vk, vkDevice, &m_colorImageCreateInfo);
+
+		// Allocate and bind color image memory
+		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
+		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
+	}
+
+	// Create stencil image
+	{
+		// Check format support
+		if (!isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_stencilFormat))
+			throw tcu::NotSupportedError(std::string("Unsupported depth/stencil format: ") + getFormatName(m_stencilFormat));
+
+		const VkImageCreateInfo stencilImageParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			VK_IMAGE_TYPE_2D,								// VkImageType			imageType;
+			m_stencilFormat,								// VkFormat				format;
+			{ m_renderSize.x(), m_renderSize.y(), 1u },		// VkExtent3D			extent;
+			1u,												// deUint32				mipLevels;
+			1u,												// deUint32				arraySize;
+			1u,												// deUint32				samples;
+			VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling		tiling;
+			VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,	// VkImageUsageFlags	usage;
+			0u,												// VkImageCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode		sharingMode;
+			1u,												// deUint32				queueFamilyCount;
+			&queueFamilyIndex,								// const deUint32*		pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED						// VkImageLayout		initialLayout;
+		};
+
+		m_stencilImage = createImage(vk, vkDevice, &stencilImageParams);
+
+		// Allocate and bind stencil image memory
+		m_stencilImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_stencilImage), MemoryRequirement::Any);
+		VK_CHECK(vk.bindImageMemory(vkDevice, *m_stencilImage, m_stencilImageAlloc->getMemory(), m_stencilImageAlloc->getOffset()));
+	}
+
+	// Create color attachment view
+	{
+		const VkImageViewCreateInfo colorAttachmentViewParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			*m_colorImage,										// VkImage						image;
+			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType				viewType;
+			m_colorFormat,										// VkFormat						format;
+			channelMappingRGBA,									// VkChannelMapping				channels;
+			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },		// VkImageSubresourceRange		subresourceRange;
+			0u													// VkImageViewCreateFlags		flags;
+		};
+
+		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
+	}
+
+	// Create stencil attachment view
+	{
+		const VkImageViewCreateInfo stencilAttachmentViewParams =
+		{
+			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			*m_stencilImage,									// VkImage						image;
+			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType				viewType;
+			m_stencilFormat,									// VkFormat						format;
+			channelMappingRGBA,									// VkChannelMapping				channels;
+			{ VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u },	// VkImageSubresourceRange		subresourceRange;
+			0u													// VkImageViewCreateFlags		flags;
+		};
+
+		m_stencilAttachmentView = createImageView(vk, vkDevice, &stencilAttachmentViewParams);
+	}
+
+	// Create render pass
+	{
+		const VkAttachmentDescription colorAttachmentDescription =
+		{
+			VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			m_colorFormat,										// VkFormat						format;
+			1u,													// 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;
+			0u													// VkAttachmentDescriptionFlags	flags;
+		};
+
+		const VkAttachmentDescription stencilAttachmentDescription =
+		{
+			VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			m_stencilFormat,									// VkFormat						format;
+			1u,													// deUint32						samples;
+			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp			loadOp;
+			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp			storeOp;
+			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp			stencilLoadOp;
+			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp			stencilStoreOp;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout				initialLayout;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout				finalLayout;
+			0u													// VkAttachmentDescriptionFlags	flags;
+		};
+
+		const VkAttachmentDescription attachments[2] =
+		{
+			colorAttachmentDescription,
+			stencilAttachmentDescription
+		};
+
+		const VkAttachmentReference colorAttachmentReference =
+		{
+			0u,													// deUint32			attachment;
+			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
+		};
+
+		const VkAttachmentReference stencilAttachmentReference =
+		{
+			1u,													// deUint32			attachment;
+			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
+		};
+
+		const VkSubpassDescription subpassDescription =
+		{
+			VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,				// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint			pipelineBindPoint;
+			0u,													// VkSubpassDescriptionFlags	flags;
+			0u,													// deUint32						inputCount;
+			DE_NULL,											// const VkAttachmentReference*	pInputAttachments;
+			1u,													// deUint32						colorCount;
+			&colorAttachmentReference,							// const VkAttachmentReference*	pColorAttachments;
+			DE_NULL,											// const VkAttachmentReference*	resolveAttachments;
+			stencilAttachmentReference,							// VkAttachmentReference		depthStencilAttachment;
+			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;
+			2u,													// deUint32							attachmentCount;
+			attachments,										// const VkAttachmentDescription*	pAttachments;
+			1u,													// deUint32							subpassCount;
+			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
+			0u,													// deUint32							dependencyCount;
+			DE_NULL												// const VkSubpassDependency*		pDependencies;
+		};
+
+		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+	}
+
+	// Create framebuffer
+	{
+		const VkImageView attachmentBindInfos[2] = { *m_colorAttachmentView, *m_stencilAttachmentView };
+
+		const VkFramebufferCreateInfo framebufferParams =
+		{
+			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			*m_renderPass,										// VkRenderPass					renderPass;
+			2u,													// deUint32						attachmentCount;
+			attachmentBindInfos,								// const VkImageView*			pAttachments;
+			(deUint32)m_renderSize.x(),							// deUint32						width;
+			(deUint32)m_renderSize.y(),							// deUint32						height;
+			1u													// deUint32						layers;
+		};
+
+		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+	}
+
+	// Create pipeline layout
+	{
+		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
+			DE_NULL,											// const void*					pNext;
+			0u,													// deUint32						descriptorSetCount;
+			DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
+			0u,													// deUint32						pushConstantRangeCount;
+			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
+		};
+
+		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+	}
+
+	// Create shaders
+	{
+		m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
+		m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
+
+		const VkShaderCreateInfo vertexShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_vertexShaderModule,							// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_VERTEX							// VkShaderStage		stage;
+		};
+
+		const VkShaderCreateInfo fragmentShaderParams =
+		{
+			VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,										// const void*			pNext;
+			*m_fragmentShaderModule,						// VkShaderModule		module;
+			"main",											// const char*			pName;
+			0u,												// VkShaderCreateFlags	flags;
+			VK_SHADER_STAGE_FRAGMENT						// VkShaderStage		stage;
+		};
+
+		m_vertexShader		= createShader(vk, vkDevice, &vertexShaderParams);
+		m_fragmentShader	= createShader(vk, vkDevice, &fragmentShaderParams);
+	}
+
+	// Create pipeline
+	{
+		const VkPipelineShaderStageCreateInfo shaderStageParams[2] =
+		{
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_VERTEX,										// VkShaderStage				stage;
+				*m_vertexShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			},
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType				sType;
+				DE_NULL,													// const void*					pNext;
+				VK_SHADER_STAGE_FRAGMENT,									// VkShaderStage				stage;
+				*m_fragmentShader,											// VkShader						shader;
+				DE_NULL														// const VkSpecializationInfo*	pSpecializationInfo;
+			}
+		};
+
+		const VkVertexInputBindingDescription vertexInputBindingDescription =
+		{
+			0u,										// deUint32					binding;
+			sizeof(Vertex4RGBA),					// deUint32					strideInBytes;
+			VK_VERTEX_INPUT_STEP_RATE_VERTEX		// VkVertexInputStepRate	stepRate;
+		};
+
+		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[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;
+				DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32	offsetInBytes;
+			}
+		};
+
+		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
+			DE_NULL,														// const void*								pNext;
+			1u,																// deUint32									bindingCount;
+			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
+			2u,																// deUint32									attributeCount;
+			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
+		};
+
+		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// VkPrimitiveTopology	topology;
+			false															// VkBool32				primitiveRestartEnable;
+		};
+
+		const VkViewport viewport =
+		{
+			0.0f,						// float	originX;
+			0.0f,						// float	originY;
+			(float)m_renderSize.x(),	// float	width;
+			(float)m_renderSize.y(),	// float	height;
+			0.0f,						// float	minDepth;
+			1.0f						// float	maxDepth;
+		};
+
+		const VkRect2D scissor = { { 0, 0 }, { m_renderSize.x(), m_renderSize.y() } };
+
+		const VkPipelineViewportStateCreateInfo viewportStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType		sType;
+			DE_NULL,														// const void*			pNext;
+			1u,																// deUint32				viewportCount;
+			&viewport,														// const VkViewport*	pViewports;
+			1u,																// deUint32				scissorCount;
+			&scissor,														// const VkRect2D*		pScissors;
+		};
+
+		const VkPipelineRasterStateCreateInfo rasterStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,			// VkStructureType	sType;
+			DE_NULL,														// const void*		pNext;
+			false,															// VkBool32			depthClipEnable;
+			false,															// VkBool32			rasterizerDiscardEnable;
+			VK_FILL_MODE_SOLID,												// VkFillMode		fillMode;
+			VK_CULL_MODE_NONE,												// VkCullMode		cullMode;
+			VK_FRONT_FACE_CCW,												// VkFrontFace		frontFace;
+			VK_FALSE,														// VkBool32			depthBiasEnable;
+			0.0f,															// float			depthBias;
+			0.0f,															// float			depthBiasClamp;
+			0.0f,															// float			slopeScaledDepthBias;
+			1.0f															// float			lineWidth;
+		};
+
+		const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+		{
+			false,																		// VkBool32			blendEnable;
+			VK_BLEND_ONE,																// VkBlend			srcBlendColor;
+			VK_BLEND_ZERO,																// VkBlend			destBlendColor;
+			VK_BLEND_OP_ADD,															// VkBlendOp		blendOpColor;
+			VK_BLEND_ONE,																// VkBlend			srcBlendAlpha;
+			VK_BLEND_ZERO,																// VkBlend			destBlendAlpha;
+			VK_BLEND_OP_ADD,															// VkBlendOp		blendOpAlpha;
+			VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT | VK_CHANNEL_A_BIT	// VkChannelFlags	channelWriteMask;
+		};
+
+		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
+			DE_NULL,													// const void*									pNext;
+			false,														// VkBool32										alphaToCoverageEnable;
+			false,														// VkBool32										alphaToOneEnable;
+			false,														// VkBool32										logicOpEnable;
+			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
+			1u,															// deUint32										attachmentCount;
+			&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
+			{ 0.0f, 0.0f, 0.0f, 0.0f }									// float										blendConst[4];
+		};
+
+		const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType			sType;
+			DE_NULL,													// const void*				pNext;
+			1u,															// deUint32					rasterSamples;
+			false,														// VkBool32					sampleShadingEnable;
+			0.0f,														// float					minSampleShading;
+			DE_NULL														// const VkSampleMask*		sampleMask;
+		};
+
+		const bool isDepthEnabled = (vk::mapVkFormat(m_stencilFormat).order != tcu::TextureFormat::S);
+
+		VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType	sType;
+			DE_NULL,													// const void*		pNext;
+			isDepthEnabled,												// VkBool32			depthTestEnable;
+			isDepthEnabled,												// VkBool32			depthWriteEnable;
+			VK_COMPARE_OP_LESS,											// VkCompareOp		depthCompareOp;
+			false,														// VkBool32			depthBoundsEnable;
+			true,														// VkBool32			stencilTestEnable;
+			m_stencilOpStateFront,										// VkStencilOpState	front;
+			m_stencilOpStateBack,										// VkStencilOpState	back;
+			-1.0f,														// float			minDepthBounds;
+			+1.0f														// float			maxDepthBounds;
+		};
+
+		const VkPipelineDynamicStateCreateInfo dynamicStateParams =
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,		// VkStructureType			sType;
+			DE_NULL,													// const void*				pNext;
+			0u,															// deUint32					dynamicStateCount;
+			DE_NULL														// const VkDynamicState*	pDynamicStates;
+		};
+
+		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+		{
+			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
+			DE_NULL,											// const void*										pNext;
+			2u,													// deUint32											stageCount;
+			shaderStageParams,									// const VkPipelineShaderStageCreateInfo*			pStages;
+			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
+			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
+			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
+			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
+			&rasterStateParams,									// const VkPipelineRasterStateCreateInfo*			pRasterState;
+			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
+			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
+			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
+			&dynamicStateParams,								// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
+			0u,													// VkPipelineCreateFlags							flags;
+			*m_pipelineLayout,									// VkPipelineLayout									layout;
+			*m_renderPass,										// VkRenderPass										renderPass;
+			0u,													// deUint32											subpass;
+			0u,													// VkPipeline										basePipelineHandle;
+			0u													// deInt32											basePipelineIndex;
+		};
+
+		// Setup different stencil masks and refs in each quad
+		for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
+		{
+			const StencilTest::StencilStateConfig&	config	= StencilTest::s_stencilStateConfigs[quadNdx];
+			VkStencilOpState&						front	= depthStencilStateParams.front;
+			VkStencilOpState&						back	= depthStencilStateParams.back;
+
+			front.stencilCompareMask	= config.frontReadMask;
+			front.stencilWriteMask		= config.frontWriteMask;
+			front.stencilReference		= config.frontRef;
+
+			back.stencilCompareMask		= config.backReadMask;
+			back.stencilWriteMask		= config.backWriteMask;
+			back.stencilReference		= config.backRef;
+
+			m_graphicsPipelines[quadNdx] = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+		}
+	}
+
+
+	// Create vertex buffer
+	{
+		const VkBufferCreateInfo vertexBufferParams =
+		{
+			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			1024u,										// VkDeviceSize			size;
+			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
+			0u,											// VkBufferCreateFlags	flags;
+			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
+			1u,											// deUint32				queueFamilyCount;
+			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
+		};
+
+		m_vertices			= createOverlappingQuads();
+		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
+		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
+
+		// Adjust depths
+		for (int quadNdx = 0; quadNdx < 4; quadNdx++)
+			for (int vertexNdx = 0; vertexNdx < 6; vertexNdx++)
+				m_vertices[quadNdx * 6 + vertexNdx].position.z() = StencilTest::s_quadDepths[quadNdx];
+
+		// Load vertices into vertex buffer
+		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
+
+		const VkMappedMemoryRange flushRange =
+		{
+				VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// VkStructureType	sType;
+				DE_NULL,								// const void*		pNext;
+				m_vertexBufferAlloc->getMemory(),		// VkDeviceMemory	mem;
+				m_vertexBufferAlloc->getOffset(),		// VkDeviceSize		offset;
+				vertexBufferParams.size					// VkDeviceSize		size;
+		};
+
+		vk.flushMappedMemoryRanges(vkDevice, 1, &flushRange);
+	}
+
+	// Create command pool
+	{
+		const VkCmdPoolCreateInfo cmdPoolParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,		// VkStructureType		sType;
+			DE_NULL,									// const void*			pNext;
+			queueFamilyIndex,							// deUint32				queueFamilyIndex;
+			VK_CMD_POOL_CREATE_TRANSIENT_BIT			// VkCmdPoolCreateFlags	flags;
+		};
+
+		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+	}
+
+	// Create command buffer
+	{
+		const VkCmdBufferCreateInfo cmdBufferParams =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			*m_cmdPool,									// VkCmdPool				cmdPool;
+			VK_CMD_BUFFER_LEVEL_PRIMARY,				// VkCmdBufferLevel			level;
+			0u											// VkCmdBufferCreateFlags	flags;
+		};
+
+		const VkCmdBufferBeginInfo cmdBufferBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,	// VkStructureType			sType;
+			DE_NULL,									// const void*				pNext;
+			0u,											// VkCmdBufferOptimizeFlags	flags;
+			DE_NULL,									// VkRenderPass				renderPass;
+			0u,											// deUint32					subpass;
+			DE_NULL										// VkFramebuffer			framebuffer;
+		};
+
+		const VkClearValue attachmentClearValues[2] =
+		{
+			defaultClearValue(m_colorFormat),
+			defaultClearValue(m_stencilFormat)
+		};
+
+		const VkRenderPassBeginInfo renderPassBeginInfo =
+		{
+			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
+			DE_NULL,												// const void*			pNext;
+			*m_renderPass,											// VkRenderPass			renderPass;
+			*m_framebuffer,											// VkFramebuffer		framebuffer;
+			{ { 0, 0 } , { m_renderSize.x(), m_renderSize.y() } },	// VkRect2D				renderArea;
+			2,														// deUint32				clearValueCount;
+			attachmentClearValues									// const VkClearValue*	pClearValues;
+		};
+
+		m_cmdBuffer = createCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
+		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_RENDER_PASS_CONTENTS_INLINE);
+
+		const VkDeviceSize		quadOffset		= (m_vertices.size() / StencilTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
+
+		for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
+		{
+			VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
+
+			vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
+			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
+			vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / StencilTest::QUAD_COUNT), 1, 0, 0);
+		}
+
+		vk.cmdEndRenderPass(*m_cmdBuffer);
+		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
+	}
+
+	// Create fence
+	{
+		const VkFenceCreateInfo fenceParams =
+		{
+			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
+			DE_NULL,								// const void*			pNext;
+			0u										// VkFenceCreateFlags	flags;
+		};
+
+		m_fence = createFence(vk, vkDevice, &fenceParams);
+	}
+}
+
+StencilTestInstance::~StencilTestInstance (void)
+{
+}
+
+tcu::TestStatus StencilTestInstance::iterate (void)
+{
+	const DeviceInterface&		vk			= m_context.getDeviceInterface();
+	const VkDevice				vkDevice	= m_context.getDevice();
+	const VkQueue				queue		= m_context.getUniversalQueue();
+
+	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
+	VK_CHECK(vk.queueSubmit(queue, 1, &m_cmdBuffer.get(), *m_fence));
+	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity*/));
+
+	return verifyImage();
+}
+
+tcu::TestStatus StencilTestInstance::verifyImage (void)
+{
+	const tcu::TextureFormat	tcuColorFormat		= mapVkFormat(m_colorFormat);
+	const tcu::TextureFormat	tcuStencilFormat	= mapVkFormat(m_stencilFormat);
+	const ColorVertexShader		vertexShader;
+	const ColorFragmentShader	fragmentShader		(tcuColorFormat, tcuStencilFormat);
+	const rr::Program			program				(&vertexShader, &fragmentShader);
+	ReferenceRenderer			refRenderer			(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
+	bool						compareOk			= false;
+
+	// Render reference image
+	{
+		// Set depth state
+		rr::RenderState renderState(refRenderer.getViewportState());
+
+		renderState.fragOps.depthTestEnabled	= true;
+		renderState.fragOps.depthFunc			= mapVkCompareOp(VK_COMPARE_OP_LESS);
+		renderState.fragOps.stencilTestEnabled	= true;
+
+		rr::StencilState& refStencilFront	= renderState.fragOps.stencilStates[rr::FACETYPE_FRONT];
+		rr::StencilState& refStencilBack	= renderState.fragOps.stencilStates[rr::FACETYPE_BACK];
+
+		refStencilFront.sFail		= mapVkStencilOp(m_stencilOpStateFront.stencilFailOp);
+		refStencilFront.dpFail		= mapVkStencilOp(m_stencilOpStateFront.stencilDepthFailOp);
+		refStencilFront.dpPass		= mapVkStencilOp(m_stencilOpStateFront.stencilPassOp);
+		refStencilFront.func		= mapVkCompareOp(m_stencilOpStateFront.stencilCompareOp);
+
+		refStencilBack.sFail		= mapVkStencilOp(m_stencilOpStateBack.stencilFailOp);
+		refStencilBack.dpFail		= mapVkStencilOp(m_stencilOpStateBack.stencilDepthFailOp);
+		refStencilBack.dpPass		= mapVkStencilOp(m_stencilOpStateBack.stencilPassOp);
+		refStencilBack.func			= mapVkCompareOp(m_stencilOpStateBack.stencilCompareOp);
+
+		// Reverse winding of vertices, as Vulkan screen coordinates start at upper left
+		std::vector<Vertex4RGBA> cwVertices(m_vertices);
+		for (size_t vertexNdx = 0; vertexNdx < cwVertices.size() - 2; vertexNdx += 3)
+		{
+			const Vertex4RGBA cwVertex1	= cwVertices[vertexNdx + 1];
+
+			cwVertices[vertexNdx + 1]	= cwVertices[vertexNdx + 2];
+			cwVertices[vertexNdx + 2]	= cwVertex1;
+		}
+
+		for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
+		{
+			refStencilFront.ref			= (int)StencilTest::s_stencilStateConfigs[quadNdx].frontRef;
+			refStencilFront.compMask	= StencilTest::s_stencilStateConfigs[quadNdx].frontReadMask;
+			refStencilFront.writeMask	= StencilTest::s_stencilStateConfigs[quadNdx].frontWriteMask;
+
+			refStencilBack.ref			= (int)StencilTest::s_stencilStateConfigs[quadNdx].backRef;
+			refStencilBack.compMask		= StencilTest::s_stencilStateConfigs[quadNdx].backReadMask;
+			refStencilBack.writeMask	= StencilTest::s_stencilStateConfigs[quadNdx].backWriteMask;
+
+			refRenderer.draw(renderState,
+							 rr::PRIMITIVETYPE_TRIANGLES,
+							 std::vector<Vertex4RGBA>(cwVertices.begin() + quadNdx * 6,
+													  cwVertices.begin() + (quadNdx + 1) * 6));
+		}
+	}
+
+	// Compare result with reference image
+	{
+		const DeviceInterface&				vk					= m_context.getDeviceInterface();
+		const VkDevice						vkDevice			= m_context.getDevice();
+		const VkQueue						queue				= m_context.getUniversalQueue();
+		const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
+		SimpleAllocator						allocator			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
+		de::UniquePtr<tcu::TextureLevel>	result				(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
+
+		compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
+															  "IntImageCompare",
+															  "Image comparison",
+															  refRenderer.getAccess(),
+															  result->getAccess(),
+															  tcu::UVec4(2, 2, 2, 2),
+															  tcu::IVec3(1, 1, 0),
+															  true,
+															  tcu::COMPARE_LOG_RESULT);
+	}
+
+	if (compareOk)
+		return tcu::TestStatus::pass("Result image matches reference");
+	else
+		return tcu::TestStatus::fail("Image mismatch");
+}
+
+
+// Utilities for test names
+
+std::string getShortName (VkCompareOp compareOp)
+{
+	const std::string  fullName = getCompareOpName(compareOp);
+
+	DE_ASSERT(de::beginsWith(fullName, "VK_COMPARE_OP_"));
+
+	return de::toLower(fullName.substr(14));
+}
+
+const char* getShortName (VkStencilOp stencilOp)
+{
+	switch (stencilOp)
+	{
+		case VK_STENCIL_OP_KEEP:			return "keep";
+		case VK_STENCIL_OP_ZERO:			return "zero";
+		case VK_STENCIL_OP_REPLACE:			return "repl";
+		case VK_STENCIL_OP_INC_CLAMP:		return "incc";
+		case VK_STENCIL_OP_DEC_CLAMP:		return "decc";
+		case VK_STENCIL_OP_INVERT:			return "inv";
+		case VK_STENCIL_OP_INC_WRAP:		return "wrap";
+		case VK_STENCIL_OP_DEC_WRAP:		return "decw";
+
+		default:
+			DE_FATAL("Invalid VkStencilOpState value");
+	}
+	return DE_NULL;
+}
+
+std::string getStencilName(const VkStencilOpState& stencilOpState)
+{
+	std::ostringstream name;
+
+	name << "fail_" << getShortName(stencilOpState.stencilFailOp)
+		 << "_pass_" << getShortName(stencilOpState.stencilPassOp)
+		 << "_dfail_" << getShortName(stencilOpState.stencilDepthFailOp)
+		 << "_comp_" << getShortName(stencilOpState.stencilCompareOp);
+
+	return name.str();
+}
+
+std::string getStencilStateSetName(const VkStencilOpState& stencilOpStateFront,
+								   const VkStencilOpState& stencilOpStateBack)
+{
+	std::ostringstream name;
+
+	name << "front_" << getStencilName(stencilOpStateFront)
+		 << "_back_" << getStencilName(stencilOpStateBack);
+
+	return name.str();
+}
+
+std::string getStencilStateSetDescription(const VkStencilOpState& stencilOpStateFront,
+										  const VkStencilOpState& stencilOpStateBack)
+{
+	std::ostringstream desc;
+
+	desc << "\nFront faces:\n" << stencilOpStateFront;
+	desc << "Back faces:\n" << stencilOpStateBack;
+
+	return desc.str();
+}
+
+std::string getFormatCaseName (VkFormat format)
+{
+	const std::string fullName = getFormatName(format);
+
+	DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
+
+	return de::toLower(fullName.substr(10));
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createStencilTests (tcu::TestContext& testCtx)
+{
+	const VkFormat stencilFormats[] =
+	{
+		VK_FORMAT_S8_UINT,
+		VK_FORMAT_D16_UNORM_S8_UINT,
+		VK_FORMAT_D24_UNORM_S8_UINT,
+		VK_FORMAT_D32_SFLOAT_S8_UINT
+	};
+
+	de::MovePtr<tcu::TestCaseGroup>		stencilTests	(new tcu::TestCaseGroup(testCtx, "stencil", "Stencil tests"));
+	de::MovePtr<tcu::TestCaseGroup>		formatTests		(new tcu::TestCaseGroup(testCtx, "format", "Uses different stencil formats"));
+	StencilOpStateUniqueRandomIterator	stencilOpItr	(123);
+
+	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(stencilFormats); formatNdx++)
+	{
+		const VkFormat					stencilFormat	= stencilFormats[formatNdx];
+		de::MovePtr<tcu::TestCaseGroup>	formatTest		(new tcu::TestCaseGroup(testCtx,
+																				getFormatCaseName(stencilFormat).c_str(),
+																				(std::string("Uses format ") + getFormatName(stencilFormat)).c_str()));
+
+		de::MovePtr<tcu::TestCaseGroup>	stencilStateTests;
+		{
+			std::ostringstream desc;
+			desc << "Draws 4 quads with the following depths and dynamic stencil states: ";
+			for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
+			{
+				const StencilTest::StencilStateConfig& stencilConfig = StencilTest::s_stencilStateConfigs[quadNdx];
+
+				desc << "(" << quadNdx << ") "
+					 << "z = " << StencilTest::s_quadDepths[quadNdx] << ", "
+					 << "frontReadMask = " << stencilConfig.frontReadMask << ", "
+					 << "frontWriteMask = " << stencilConfig.frontWriteMask << ", "
+					 << "frontRef = " << stencilConfig.frontRef << ", "
+					 << "backReadMask = " << stencilConfig.backReadMask << ", "
+					 << "backWriteMask = " << stencilConfig.backWriteMask << ", "
+					 << "backRef = " << stencilConfig.backRef;
+			}
+
+			stencilStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", desc.str().c_str()));
+		}
+
+		stencilOpItr.reset();
+
+		VkStencilOpState		prevStencilState	= stencilOpItr.next();
+		const VkStencilOpState	firstStencilState	= prevStencilState;
+
+		while (stencilOpItr.hasNext())
+		{
+			const VkStencilOpState stencilState = stencilOpItr.next();
+
+			// Use current stencil state in front fraces and previous state in back faces
+			stencilStateTests->addChild(new StencilTest(testCtx,
+														getStencilStateSetName(stencilState, prevStencilState),
+														getStencilStateSetDescription(stencilState, prevStencilState),
+														stencilFormat,
+														stencilState,
+														prevStencilState));
+
+			prevStencilState = stencilState;
+		}
+
+		// Use first stencil state with last stencil state. This would make the test suite cover all states in front and back faces.
+		stencilStateTests->addChild(new StencilTest(testCtx,
+													getStencilStateSetName(firstStencilState, prevStencilState),
+													getStencilStateSetDescription(firstStencilState, prevStencilState),
+													stencilFormat,
+													firstStencilState,
+													prevStencilState));
+
+		formatTest->addChild(stencilStateTests.release());
+		formatTests->addChild(formatTest.release());
+	}
+	stencilTests->addChild(formatTests.release());
+
+	return stencilTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.hpp
new file mode 100644
index 0000000..fe0ec20
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineStencilTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTPIPELINESTENCILTESTS_HPP
+#define _VKTPIPELINESTENCILTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Stencil Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createStencilTests (tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINESTENCILTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
new file mode 100644
index 0000000..4df391e
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.cpp
@@ -0,0 +1,59 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Pipeline Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineTests.hpp"
+#include "vktPipelineStencilTests.hpp"
+#include "vktPipelineBlendTests.hpp"
+#include "vktPipelineDepthTests.hpp"
+#include "deUniquePtr.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup> pipelineTests (new tcu::TestCaseGroup(testCtx, "pipeline", "Pipeline Tests"));
+
+	pipelineTests->addChild(createStencilTests(testCtx));
+	pipelineTests->addChild(createBlendTests(testCtx));
+	pipelineTests->addChild(createDepthTests(testCtx));
+
+	return pipelineTests.release();
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.hpp
new file mode 100644
index 0000000..cb1c470
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineTests.hpp
@@ -0,0 +1,51 @@
+#ifndef _VKTPIPELINETESTS_HPP
+#define _VKTPIPELINETESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Pipeline Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+tcu::TestCaseGroup*		createTests			(tcu::TestContext& testCtx);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINETESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineUniqueRandomIterator.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineUniqueRandomIterator.hpp
new file mode 100644
index 0000000..7ad6b30
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineUniqueRandomIterator.hpp
@@ -0,0 +1,140 @@
+#ifndef _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+#define _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Iterator over a unique sequence of items
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "deRandom.hpp"
+#include <set>
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+template <typename T>
+class UniqueRandomIterator
+{
+public:
+							UniqueRandomIterator	(deUint32 numItems, deUint32 numValues, int seed);
+	virtual					~UniqueRandomIterator	(void) {}
+	bool					hasNext					(void) const;
+	T						next					(void);
+	void					reset					(void);
+
+protected:
+	virtual T				getIndexedValue			(deUint32 index) = 0;
+
+private:
+	std::vector<deUint32>	m_indices;
+	size_t					m_currentIndex;
+};
+
+class RandomFunction
+{
+private:
+	de::Random m_random;
+
+public:
+	RandomFunction(int seed)
+		: m_random(seed)
+	{}
+
+	virtual ~RandomFunction() {}
+
+	deUint32 operator()(deUint32 max)
+	{
+		return m_random.getUint32() % max;
+	}
+};
+
+template <typename T>
+UniqueRandomIterator<T>::UniqueRandomIterator (deUint32 numItems, deUint32 numValues, int seed)
+{
+	DE_ASSERT(numItems <= numValues);
+
+	RandomFunction randomFunc(seed);
+
+	if (numItems == numValues)
+	{
+		// Fast way to populate the index sequence
+		m_indices = std::vector<deUint32>(numItems);
+
+		for (deUint32 itemNdx = 0; itemNdx < numItems; itemNdx++)
+			m_indices[itemNdx] = itemNdx;
+	}
+	else
+	{
+		std::set<deUint32> uniqueIndices;
+
+		// Populate set with "numItems" unique values between 0 and numValues - 1
+		while (uniqueIndices.size() < numItems)
+			uniqueIndices.insert(randomFunc(numValues));
+
+		// Copy set into index sequence
+		m_indices = std::vector<deUint32>(uniqueIndices.begin(), uniqueIndices.end());
+	}
+
+	// Scramble the indices
+	std::random_shuffle(m_indices.begin(), m_indices.end(), randomFunc);
+
+	reset();
+}
+
+template <typename T>
+bool UniqueRandomIterator<T>::hasNext (void) const
+{
+	return m_currentIndex < m_indices.size();
+}
+
+template <typename T>
+T UniqueRandomIterator<T>::next (void)
+{
+	DE_ASSERT(m_currentIndex < m_indices.size());
+
+	return getIndexedValue(m_indices[m_currentIndex++]);
+}
+
+template <typename T>
+void UniqueRandomIterator<T>::reset (void)
+{
+	m_currentIndex = 0;
+}
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEUNIQUERANDOMITERATOR_HPP
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.cpp
new file mode 100644
index 0000000..113a70d
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.cpp
@@ -0,0 +1,110 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for vertex buffers.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktPipelineVertexUtil.hpp"
+#include "tcuVectorUtil.hpp"
+
+namespace vkt
+{
+namespace pipeline
+{
+
+std::vector<Vertex4RGBA> createOverlappingQuads (void)
+{
+	using tcu::Vec2;
+	using tcu::Vec4;
+
+	std::vector<Vertex4RGBA> vertices;
+
+	const Vec2 translations[4] =
+	{
+		Vec2(-0.25f, -0.25f),
+		Vec2(-1.0f, -0.25f),
+		Vec2(-1.0f, -1.0f),
+		Vec2(-0.25f, -1.0f)
+	};
+
+	const Vec4 quadColors[4] =
+	{
+		Vec4(1.0f, 0.0f, 0.0f, 1.0),
+		Vec4(0.0f, 1.0f, 0.0f, 1.0),
+		Vec4(0.0f, 0.0f, 1.0f, 1.0),
+		Vec4(1.0f, 0.0f, 1.0f, 1.0)
+	};
+
+	const float quadSize = 1.25f;
+
+	for (int quadNdx = 0; quadNdx < 4; quadNdx++)
+	{
+		const Vec2&	translation	= translations[quadNdx];
+		const Vec4&	color		= quadColors[quadNdx];
+
+		const Vertex4RGBA lowerLeftVertex =
+		{
+			Vec4(translation.x(), translation.y(), 0.0f, 1.0f),
+			color
+		};
+		const Vertex4RGBA upperLeftVertex =
+		{
+			Vec4(translation.x(), translation.y() + quadSize, 0.0f, 1.0f),
+			color
+		};
+		const Vertex4RGBA lowerRightVertex =
+		{
+			Vec4(translation.x() + quadSize, translation.y(), 0.0f, 1.0f),
+			color
+		};
+		const Vertex4RGBA upperRightVertex =
+		{
+			Vec4(translation.x() + quadSize, translation.y() + quadSize, 0.0f, 1.0f),
+			color
+		};
+
+		// Triangle 1, CCW
+		vertices.push_back(lowerLeftVertex);
+		vertices.push_back(lowerRightVertex);
+		vertices.push_back(upperLeftVertex);
+
+		// Triangle 2, CW
+		vertices.push_back(lowerRightVertex);
+		vertices.push_back(upperLeftVertex);
+		vertices.push_back(upperRightVertex);
+	}
+
+	return vertices;
+}
+
+} // pipeline
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.hpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.hpp
new file mode 100644
index 0000000..02dfbe9
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexUtil.hpp
@@ -0,0 +1,65 @@
+#ifndef _VKTPIPELINEVERTEXUTIL_HPP
+#define _VKTPIPELINEVERTEXUTIL_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utilities for vertex buffers.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include <vector>
+
+namespace vkt
+{
+namespace pipeline
+{
+
+struct Vertex4RGBA
+{
+	tcu::Vec4 position;
+	tcu::Vec4 color;
+};
+
+/*! \brief Creates a pattern of 4 overlapping quads.
+ *
+ *  The quads are alined along the plane Z = 0, with X,Y taking values between -1 and 1.
+ *  Each quad covers one of the quadrants of the scene and partially extends to the other 3 quadrants.
+ *  The triangles of each quad have different winding orders (CW/CCW).
+ */
+std::vector<Vertex4RGBA> createOverlappingQuads (void);
+
+} // pipeline
+} // vkt
+
+#endif // _VKTPIPELINEVERTEXUTIL_HPP
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/CMakeLists.txt b/external/vulkancts/modules/vulkan/spirv_assembly/CMakeLists.txt
new file mode 100644
index 0000000..1dbd6d6
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/CMakeLists.txt
@@ -0,0 +1,22 @@
+# SPIR-V assembly tests
+
+include_directories(..)
+
+set(DEQP_VK_SPIRV_ASSEMBLY_SRCS
+	vktSpvAsmComputeShaderCase.cpp
+	vktSpvAsmComputeShaderCase.hpp
+	vktSpvAsmComputeShaderTestUtil.cpp
+	vktSpvAsmComputeShaderTestUtil.hpp
+	vktSpvAsmInstructionTests.cpp
+	vktSpvAsmInstructionTests.hpp
+	vktSpvAsmTests.cpp
+	vktSpvAsmTests.hpp
+	)
+
+set(DEQP_VK_SPIRV_ASSEMBLY_LIBS
+	tcutil
+	vkutil
+	)
+
+add_library(deqp-vk-spirv-assembly STATIC ${DEQP_VK_SPIRV_ASSEMBLY_SRCS})
+target_link_libraries(deqp-vk-spirv-assembly ${DEQP_VK_SPIRV_ASSEMBLY_LIBS})
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp
new file mode 100644
index 0000000..1ff3dfe
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.cpp
@@ -0,0 +1,417 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Test Case Skeleton Based on Compute Shaders
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmComputeShaderCase.hpp"
+
+#include "deSharedPtr.hpp"
+
+#include "vkBuilderUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+namespace
+{
+
+using namespace vk;
+using std::vector;
+
+typedef de::MovePtr<Allocation>			AllocationMp;
+typedef de::SharedPtr<Allocation>		AllocationSp;
+typedef Unique<VkBuffer>				BufferHandleUp;
+typedef de::SharedPtr<BufferHandleUp>	BufferHandleSp;
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create storage buffer, allocate and bind memory for the buffer
+ *
+ * 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)
+{
+	const VkBufferCreateInfo bufferCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// sType
+		DE_NULL,								// pNext
+		numBytes,								// size
+		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// usage
+		0u,										// flags
+		VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
+		0u,										// queueFamilyCount
+		DE_NULL,								// pQueueFamilyIndices
+	};
+
+	Move<VkBuffer>				buffer			(createBuffer(vkdi, device, &bufferCreateInfo));
+	const VkMemoryRequirements	requirements	= getBufferMemoryRequirements(vkdi, device, *buffer);
+	AllocationMp				bufferMemory	= allocator.allocate(requirements, MemoryRequirement::HostVisible);
+
+	VK_CHECK(vkdi.bindBufferMemory(device, *buffer, bufferMemory->getMemory(), bufferMemory->getOffset()));
+	*outMemory = bufferMemory;
+
+	return buffer;
+}
+
+void setMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes, const void* data)
+{
+	void* const hostPtr = destAlloc->getHostPtr();
+
+	deMemcpy((deUint8*)hostPtr, data, numBytes);
+	flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
+}
+
+void clearMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes)
+{
+	void* const hostPtr = destAlloc->getHostPtr();
+
+	deMemset((deUint8*)hostPtr, 0, numBytes);
+	flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
+}
+
+VkDescriptorInfo createDescriptorInfo (VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range)
+{
+	const VkDescriptorInfo info =
+	{
+		0,							// bufferView
+		0,							// sampler
+		0,							// imageView
+		(VkImageLayout)0,			// imageLayout
+		{ buffer, offset, range },	// bufferInfo
+	};
+
+	return info;
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a descriptor set layout with numBindings descriptors
+ *
+ * All descriptors are created for shader storage buffer objects and
+ * compute pipeline.
+ *//*--------------------------------------------------------------------*/
+Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkdi, const VkDevice& device, size_t numBindings)
+{
+	DescriptorSetLayoutBuilder builder;
+
+	for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
+		builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
+
+	return builder.build(vkdi, device);
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a pipeline layout with one descriptor set
+ *//*--------------------------------------------------------------------*/
+Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorSetLayout descriptorSetLayout)
+{
+	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// sType
+		DE_NULL,										// pNext
+		1u,												// descriptorSetCount
+		&descriptorSetLayout,							// pSetLayouts
+		0u,												// pushConstantRangeCount
+		DE_NULL,										// pPushConstantRanges
+	};
+
+	return createPipelineLayout(vkdi, device, &pipelineLayoutCreateInfo);
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a one-time descriptor pool for one descriptor set
+ *
+ * The pool supports numDescriptors storage buffer descriptors.
+ *//*--------------------------------------------------------------------*/
+inline Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkdi, const VkDevice& device, deUint32 numDescriptors)
+{
+	return DescriptorPoolBuilder()
+		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, numDescriptors)
+		.build(vkdi, device, VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, /* 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.
+ *//*--------------------------------------------------------------------*/
+Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorPool pool, VkDescriptorSetLayout layout, size_t numViews, const vector<VkDescriptorInfo>& descriptorInfos)
+{
+	Move<VkDescriptorSet>		descriptorSet	= allocDescriptorSet(vkdi, device, pool, VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, layout);
+	DescriptorSetUpdateBuilder	builder;
+
+	for (deUint32 descriptorNdx = 0; descriptorNdx < numViews; ++descriptorNdx)
+		builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descriptorNdx), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfos[descriptorNdx]);
+	builder.update(vkdi, device);
+
+	return descriptorSet;
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a shader from the given shader module
+ *
+ * The entry point of the shader is assumed to be "main".
+ *//*--------------------------------------------------------------------*/
+Move<VkShader> createShader (const DeviceInterface& vkdi, const VkDevice& device, VkShaderModule module)
+{
+	const VkShaderCreateInfo shaderCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,	// sType
+		DE_NULL,								// pNext
+		module,									// module
+		"main",									// pName
+		0u,										// flags
+		VK_SHADER_STAGE_COMPUTE,				// stage
+	};
+
+	return createShader(vkdi, device, &shaderCreateInfo);
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a compute pipeline based on the given shader
+ *//*--------------------------------------------------------------------*/
+Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShader shader)
+{
+	const VkPipelineShaderStageCreateInfo	pipelineShaderStageCreateInfo	=
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
+		DE_NULL,												// pNext
+		VK_SHADER_STAGE_COMPUTE,								// stage
+		shader,													// shader
+		DE_NULL,												// pSpecializationInfo
+	};
+	const VkComputePipelineCreateInfo		pipelineCreateInfo				=
+	{
+		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,			// sType
+		DE_NULL,												// pNext
+		pipelineShaderStageCreateInfo,							// cs
+		0u,														// flags
+		pipelineLayout,											// layout
+		(VkPipeline)0,											// basePipelineHandle
+		0u,														// basePipelineIndex
+	};
+
+	return createComputePipeline(vkdi, device, (VkPipelineCache)0u, &pipelineCreateInfo);
+}
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Create a command pool
+ *
+ * The created command pool is designated for use on the queue type
+ * represented by the given queueFamilyIndex.
+ *//*--------------------------------------------------------------------*/
+Move<VkCmdPool> createCommandPool (const DeviceInterface& vkdi, VkDevice device, deUint32 queueFamilyIndex)
+{
+	const VkCmdPoolCreateInfo cmdPoolCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,	// sType
+		DE_NULL,								// pNext
+		queueFamilyIndex,						// queueFamilyIndex
+		0u										// flags
+	};
+
+	return createCommandPool(vkdi, device, &cmdPoolCreateInfo);
+}
+
+} // anonymous
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Test instance for compute pipeline
+ *
+ * The compute shader is specified in the format of SPIR-V assembly, which
+ * is allowed to access MAX_NUM_INPUT_BUFFERS input storage buffers and
+ * MAX_NUM_OUTPUT_BUFFERS output storage buffers maximally. The shader
+ * source and input/output data are given in a ComputeShaderSpec object.
+ *
+ * This instance runs the given compute shader by feeding the data from input
+ * buffers and compares the data in the output buffers with the expected.
+ *//*--------------------------------------------------------------------*/
+class SpvAsmComputeShaderInstance : public TestInstance
+{
+public:
+								SpvAsmComputeShaderInstance	(Context& ctx, const ComputeShaderSpec& spec);
+	tcu::TestStatus				iterate						(void);
+
+private:
+	const ComputeShaderSpec&	m_shaderSpec;
+};
+
+// ComputeShaderTestCase implementations
+
+SpvAsmComputeShaderCase::SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec)
+	: TestCase		(testCtx, name, description)
+	, m_shaderSpec	(spec)
+{
+}
+
+void SpvAsmComputeShaderCase::initPrograms (SourceCollections& programCollection) const
+{
+	programCollection.spirvAsmSources.add("compute") << m_shaderSpec.assembly.c_str();
+}
+
+TestInstance* SpvAsmComputeShaderCase::createInstance (Context& ctx) const
+{
+	return new SpvAsmComputeShaderInstance(ctx, m_shaderSpec);
+}
+
+// ComputeShaderTestInstance implementations
+
+SpvAsmComputeShaderInstance::SpvAsmComputeShaderInstance (Context& ctx, const ComputeShaderSpec& spec)
+	: TestInstance	(ctx)
+	, m_shaderSpec	(spec)
+{
+}
+
+tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
+{
+	const DeviceInterface&			vkdi				= m_context.getDeviceInterface();
+	const VkDevice&					device				= m_context.getDevice();
+	Allocator&						allocator			= m_context.getDefaultAllocator();
+
+	vector<AllocationSp>			inputAllocs;
+	vector<AllocationSp>			outputAllocs;
+	vector<BufferHandleSp>			inputBuffers;
+	vector<BufferHandleSp>			outputBuffers;
+	vector<VkDescriptorInfo>		descriptorInfos;
+
+	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)
+	{
+		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));
+
+		setMemory(vkdi, device, &*alloc, numBytes, input->data());
+		descriptorInfos.push_back(createDescriptorInfo(**buffer, 0u, numBytes));
+		inputBuffers.push_back(BufferHandleSp(buffer));
+		inputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
+	}
+
+	for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+	{
+		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));
+
+		clearMemory(vkdi, device, &*alloc, numBytes);
+		descriptorInfos.push_back(createDescriptorInfo(**buffer, 0u, numBytes));
+		outputBuffers.push_back(BufferHandleSp(buffer));
+		outputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
+	}
+
+	// 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));
+
+	// Create compute shader and pipeline.
+
+	const ProgramBinary&			binary				= m_context.getBinaryCollection().get("compute");
+	Unique<VkShaderModule>			module				(createShaderModule(vkdi, device, binary, (VkShaderModuleCreateFlags)0u));
+	Unique<VkShader>				shader				(createShader(vkdi, device, *module));
+
+	Unique<VkPipeline>				computePipeline		(createComputePipeline(vkdi, device, *pipelineLayout, *shader));
+
+	// Create command buffer and record commands
+
+	const Unique<VkCmdPool>			cmdPool				(createCommandPool(vkdi, device, m_context.getUniversalQueueFamilyIndex()));
+	const VkCmdBufferCreateInfo		cmdBufferCreateInfo	=
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// sType
+		NULL,										// pNext
+		*cmdPool,									// cmdPool
+		VK_CMD_BUFFER_LEVEL_PRIMARY,				// level
+		0u											// flags
+	};
+
+	Unique<VkCmdBuffer>				cmdBuffer			(createCommandBuffer(vkdi, device, &cmdBufferCreateInfo));
+
+	const VkCmdBufferBeginInfo		cmdBufferBeginInfo	=
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,	// sType
+		DE_NULL,									// pNext
+		VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,	// flags
+		(VkRenderPass)0u,							// renderPass
+		0u,											// subpass
+		(VkFramebuffer)0u,							// framebuffer
+	};
+
+	const tcu::IVec3&				numWorkGroups		= m_shaderSpec.numWorkGroups;
+
+	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);
+	vkdi.cmdDispatch(*cmdBuffer, numWorkGroups.x(), numWorkGroups.y(), numWorkGroups.z());
+	VK_CHECK(vkdi.endCommandBuffer(*cmdBuffer));
+
+	// Create fence and run.
+
+	const VkFenceCreateInfo			fenceCreateInfo		=
+	{
+		 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,		// sType
+		 NULL,										// pNext
+		 0											// flags
+    };
+	const Unique<VkFence>			cmdCompleteFence	(createFence(vkdi, device, &fenceCreateInfo));
+	const deUint64					infiniteTimeout		= ~(deUint64)0u;
+
+	VK_CHECK(vkdi.queueSubmit(m_context.getUniversalQueue(), 1, &cmdBuffer.get(), *cmdCompleteFence));
+	VK_CHECK(vkdi.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
+
+	// Check output.
+
+	for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+	{
+		const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
+		if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
+			return tcu::TestStatus::fail("Output doesn't match with expected");
+	}
+
+	return tcu::TestStatus::pass("Ouput match with expected");
+}
+
+} // SpirVAssembly
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.hpp
new file mode 100644
index 0000000..4051fad
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderCase.hpp
@@ -0,0 +1,61 @@
+#ifndef _VKTSPVASMCOMPUTESHADERCASE_HPP
+#define _VKTSPVASMCOMPUTESHADERCASE_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Test Case Skeleton Based on Compute Shaders
+ *//*--------------------------------------------------------------------*/
+
+#include "vkPrograms.hpp"
+#include "vktTestCase.hpp"
+
+#include "vktSpvAsmComputeShaderTestUtil.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+class SpvAsmComputeShaderCase : public TestCase
+{
+public:
+						SpvAsmComputeShaderCase	(tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec);
+	void				initPrograms			(vk::SourceCollections& programCollection) const;
+	TestInstance*		createInstance			(Context& ctx) const;
+
+private:
+	ComputeShaderSpec	m_shaderSpec;
+};
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMCOMPUTESHADERCASE_HPP
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.cpp
new file mode 100644
index 0000000..7e9a1d3
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.cpp
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Compute Shader Based Test Case Utility Structs/Functions
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmComputeShaderTestUtil.hpp"
+
+DE_EMPTY_CPP_FILE
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp
new file mode 100644
index 0000000..fbfa5c0
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmComputeShaderTestUtil.hpp
@@ -0,0 +1,101 @@
+#ifndef _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
+#define _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Compute Shader Based Test Case Utility Structs/Functions
+ *//*--------------------------------------------------------------------*/
+
+#include "deDefs.h"
+#include "deSharedPtr.hpp"
+#include "tcuVector.hpp"
+
+#include <string>
+#include <vector>
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Abstract class for an input/output storage buffer object
+ *//*--------------------------------------------------------------------*/
+class BufferInterface
+{
+public:
+	virtual				~BufferInterface	(void)				{}
+
+	virtual size_t		getNumBytes			(void) const = 0;
+	virtual const void*	data				(void) const = 0;
+};
+
+typedef de::SharedPtr<BufferInterface>		BufferSp;
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Concrete class for an input/output storage buffer object
+ *//*--------------------------------------------------------------------*/
+template<typename E>
+class Buffer : public BufferInterface
+{
+public:
+						Buffer				(const std::vector<E>& elements)
+							: m_elements(elements)
+						{}
+
+	size_t				getNumBytes			(void) const		{ return m_elements.size() * sizeof(E); }
+	const void*			data				(void) const		{ return &m_elements.front(); }
+
+private:
+	std::vector<E>		m_elements;
+};
+
+typedef Buffer<float>	Float32Buffer;
+
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Specification for a compute shader.
+ *
+ * This struct bundles SPIR-V assembly code, input and expected output
+ * together.
+ *//*--------------------------------------------------------------------*/
+struct ComputeShaderSpec
+{
+	std::string				assembly;
+	std::vector<BufferSp>	inputs;
+	std::vector<BufferSp>	outputs;
+	tcu::IVec3				numWorkGroups;
+};
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
new file mode 100644
index 0000000..7645422
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
@@ -0,0 +1,168 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V Assembly Tests for Instructions (special opcode/operand)
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmInstructionTests.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include "vktSpvAsmComputeShaderCase.hpp"
+#include "vktSpvAsmComputeShaderTestUtil.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+namespace
+{
+
+using std::vector;
+using tcu::IVec3;
+
+SpvAsmComputeShaderCase* createOpNopTestCase (tcu::TestContext& testCtx)
+{
+	ComputeShaderSpec spec;
+	// Based on GLSL source code:
+	//
+	// #version 430
+	//
+	// layout(std140, set = 0, binding = 0) readonly buffer Input {
+	//   float elements[];
+	// } input_data;
+	// layout(std140, set = 0, binding = 1) writeonly buffer Output {
+	//   float elements[];
+	// } output_data;
+	//
+	// layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+	//
+	// void main() {
+	//   uint x = gl_GlobalInvocationID.x;
+	//   output_data.elements[x] = -input_data.elements[x];
+	// }
+	spec.assembly =
+		"OpNop\n" // As the first instruction
+
+		"OpSource GLSL 430\n"
+		"OpCapability Shader\n"
+		"%std450 = OpExtInstImport \"GLSL.std.450\"\n"
+		"OpMemoryModel Logical GLSL450\n"
+
+		"OpEntryPoint GLCompute %main \"main\" %id\n"
+
+		"OpNop\n" // After OpEntryPoint but before any type definitions
+
+		"OpExecutionMode %main LocalSize 1 1 1\n"
+
+		"OpName %main           \"main\"\n"
+		"OpName %id             \"gl_GlobalInvocationID\"\n"
+		"OpName %outbuf         \"Output\"\n"
+		"OpMemberName %outbuf 0 \"elements\"\n"
+		"OpName %outdata        \"output_data\"\n"
+		"OpName %inbuf          \"Input\"\n"
+		"OpMemberName %inbuf 0  \"elements\"\n"
+		"OpName %indata         \"input_data\"\n"
+
+		"OpDecorate %id BuiltIn GlobalInvocationId\n"
+		"OpDecorate %inbuf BufferBlock\n"
+		"OpDecorate %indata DescriptorSet 0\n"
+		"OpDecorate %indata Binding 0\n"
+		"OpDecorate %outbuf BufferBlock\n"
+		"OpDecorate %outdata DescriptorSet 0\n"
+		"OpDecorate %outdata Binding 1\n"
+		"OpDecorate %f32arr ArrayStride 4\n"
+		"OpMemberDecorate %inbuf 0 Offset 0\n"
+		"OpMemberDecorate %outbuf 0 Offset 0\n"
+
+		"%void      = OpTypeVoid\n"
+		"%voidf     = OpTypeFunction %void\n"
+
+		"             OpNop\n" // In the middle of type definitions
+
+		"%u32       = OpTypeInt 32 0\n"
+		"%uvec3     = OpTypeVector %u32 3\n"
+		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
+		"%f32       = OpTypeFloat 32\n"
+		"%f32ptr    = OpTypePointer Uniform %f32\n"
+		"%f32arr    = OpTypeRuntimeArray %f32\n"
+		"%outbuf    = OpTypeStruct %f32arr\n"
+		"%outbufptr = OpTypePointer Uniform %outbuf\n"
+		"%inbuf     = OpTypeStruct %f32arr\n"
+		"%inbufptr  = OpTypePointer Uniform %inbuf\n"
+		"%i32       = OpTypeInt 32 1\n"
+
+		"%id        = OpVariable %uvec3ptr Input\n"
+		"%indata    = OpVariable %inbufptr Uniform\n"
+		"%outdata   = OpVariable %outbufptr Uniform\n"
+		"%zero      = OpConstant %i32 0\n"
+
+		"%main      = OpFunction %void None %voidf\n"
+		"%label     = OpLabel\n"
+		"%idval     = OpLoad %uvec3 %id\n"
+		"%x         = OpCompositeExtract %u32 %idval 0\n"
+
+		"             OpNop\n" // Inside a function body
+
+		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
+		"%inval     = OpLoad %f32 %inloc\n"
+		"%neg       = OpFNegate %f32 %inval\n"
+		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
+		"             OpStore %outloc %neg\n"
+		"             OpReturn\n"
+		"             OpFunctionEnd\n";
+
+	const int numElements = 100;
+	vector<float> positiveFloats(numElements, 42.42f);
+	vector<float> negativeFloats(numElements, -42.42f);
+
+	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
+	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
+
+	spec.numWorkGroups = IVec3(numElements, 1, 1);
+
+	return new SpvAsmComputeShaderCase(testCtx, "opnop", "Test the OpNop instruction", spec);
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup> instructionTests (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
+
+	instructionTests->addChild(createOpNopTestCase(testCtx));
+
+	return instructionTests.release();
+}
+
+} // SpirVAssembly
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.hpp
new file mode 100644
index 0000000..29587db
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTSPVASMINSTRUCTIONTESTS_HPP
+#define _VKTSPVASMINSTRUCTIONTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V Assembly Tests for Instructions (special opcode/operand)
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx);
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMINSTRUCTIONTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.cpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.cpp
new file mode 100644
index 0000000..52c78d6
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.cpp
@@ -0,0 +1,59 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktSpvAsmTests.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include "vktSpvAsmInstructionTests.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup> spirVAssemblyTests (new tcu::TestCaseGroup(testCtx, "spirv_assembly", "SPIR-V Assembly tests"));
+
+	spirVAssemblyTests->addChild(createInstructionTests(testCtx));
+	// \todo [2015-09-28 antiagainst] control flow
+	// \todo [2015-09-28 antiagainst] multiple entry points for the same shader stage
+	// \todo [2015-09-28 antiagainst] multiple shaders in the same module
+
+	return spirVAssemblyTests.release();
+}
+
+} // SpirVAssembly
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.hpp b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.hpp
new file mode 100644
index 0000000..c2d3f14
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.hpp
@@ -0,0 +1,50 @@
+#ifndef _VKTSPVASMESTS_HPP
+#define _VKTSPVASMESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V Assembly Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx);
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/vktBuildPrograms.cpp b/external/vulkancts/modules/vulkan/vktBuildPrograms.cpp
new file mode 100644
index 0000000..864c5d7
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktBuildPrograms.cpp
@@ -0,0 +1,282 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Utility for pre-compiling source programs to SPIR-V
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuCommandLine.hpp"
+#include "tcuPlatform.hpp"
+#include "tcuResource.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTestHierarchyIterator.hpp"
+#include "deUniquePtr.hpp"
+#include "vkPrograms.hpp"
+#include "vkBinaryRegistry.hpp"
+#include "vktTestCase.hpp"
+#include "vktTestPackage.hpp"
+#include "deUniquePtr.hpp"
+#include "deCommandLine.hpp"
+
+#include <iostream>
+
+using std::vector;
+using std::string;
+using de::UniquePtr;
+using de::MovePtr;
+
+namespace vkt
+{
+
+tcu::TestPackageRoot* createRoot (tcu::TestContext& testCtx)
+{
+	vector<tcu::TestNode*>	children;
+	children.push_back(new TestPackage(testCtx));
+	return new tcu::TestPackageRoot(testCtx, children);
+}
+
+enum BuildMode
+{
+	BUILDMODE_BUILD = 0,
+	BUILDMODE_VERIFY,
+
+	BUILDMODE_LAST
+};
+
+struct BuildStats
+{
+	int		numSucceeded;
+	int		numFailed;
+
+	BuildStats (void)
+		: numSucceeded	(0)
+		, numFailed		(0)
+	{
+	}
+};
+
+namespace // anonymous
+{
+
+vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
+{
+	return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
+}
+
+vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
+{
+	return vk::assembleProgram(source, buildInfo);
+}
+
+void writeVerboseLogs (const glu::ShaderProgramInfo& buildInfo)
+{
+	for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
+	{
+		const glu::ShaderInfo&	shaderInfo	= buildInfo.shaders[shaderNdx];
+		const char* const		shaderName	= getShaderTypeName(shaderInfo.type);
+
+		tcu::print("%s source:\n---\n%s\n---\n", shaderName, shaderInfo.source.c_str());
+		tcu::print("%s compile log:\n---\n%s\n---\n", shaderName, shaderInfo.infoLog.c_str());
+	}
+}
+
+void writeVerboseLogs (const vk::SpirVProgramInfo& buildInfo)
+{
+	tcu::print("source:\n---\n%s\n---\n", buildInfo.source->program.str().c_str());
+	tcu::print("compile log:\n---\n%s\n---\n", buildInfo.infoLog.c_str());
+}
+
+template <typename InfoType, typename IteratorType>
+void buildProgram (const std::string&			casePath,
+				   bool							printLogs,
+				   IteratorType					iter,
+				   BuildMode					mode,
+				   BuildStats*					stats,
+				   vk::BinaryRegistryReader*	reader,
+				   vk::BinaryRegistryWriter*	writer)
+{
+	InfoType							buildInfo;
+	try
+	{
+		const vk::ProgramIdentifier			progId		(casePath, iter.getName());
+		const UniquePtr<vk::ProgramBinary>	binary		(compileProgram(iter.getProgram(), &buildInfo));
+
+		if (mode == BUILDMODE_BUILD)
+			writer->storeProgram(progId, *binary);
+		else
+		{
+			DE_ASSERT(mode == BUILDMODE_VERIFY);
+
+			const UniquePtr<vk::ProgramBinary>	storedBinary	(reader->loadProgram(progId));
+
+			if (binary->getSize() != storedBinary->getSize())
+				throw tcu::Exception("Binary size doesn't match");
+
+			if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
+				throw tcu::Exception("Binary contents don't match");
+		}
+
+		tcu::print("  OK: %s\n", iter.getName().c_str());
+		stats->numSucceeded += 1;
+	}
+	catch (const std::exception& e)
+	{
+		tcu::print("  ERROR: %s: %s\n", iter.getName().c_str(), e.what());
+		if (printLogs)
+		{
+			writeVerboseLogs(buildInfo);
+		}
+		stats->numFailed += 1;
+	}
+}
+
+} // anonymous
+BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, BuildMode mode, bool verbose)
+{
+	const UniquePtr<tcu::TestPackageRoot>	root		(createRoot(testCtx));
+	tcu::DefaultHierarchyInflater			inflater	(testCtx);
+	tcu::TestHierarchyIterator				iterator	(*root, inflater, testCtx.getCommandLine());
+	const tcu::DirArchive					srcArchive	(dstPath.c_str());
+	UniquePtr<vk::BinaryRegistryWriter>		writer		(mode == BUILDMODE_BUILD	? new vk::BinaryRegistryWriter(dstPath)			: DE_NULL);
+	UniquePtr<vk::BinaryRegistryReader>		reader		(mode == BUILDMODE_VERIFY	? new vk::BinaryRegistryReader(srcArchive, "")	: DE_NULL);
+	BuildStats								stats;
+	const bool								printLogs	= verbose;
+
+	while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
+	{
+		if (iterator.getState() == tcu::TestHierarchyIterator::STATE_ENTER_NODE &&
+			tcu::isTestNodeTypeExecutable(iterator.getNode()->getNodeType()))
+		{
+			const TestCase* const		testCase	= dynamic_cast<TestCase*>(iterator.getNode());
+			const string				casePath	= iterator.getNodePath();
+			vk::SourceCollections		progs;
+
+			tcu::print("%s\n", casePath.c_str());
+
+			testCase->initPrograms(progs);
+
+			for (vk::GlslSourceCollection::Iterator progIter = progs.glslSources.begin(); progIter != progs.glslSources.end(); ++progIter)
+			{
+				buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
+			}
+
+			for (vk::SpirVAsmCollection::Iterator progIter = progs.spirvAsmSources.begin(); progIter != progs.spirvAsmSources.end(); ++progIter)
+			{
+				buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
+			}
+		}
+
+		iterator.next();
+	}
+
+	return stats;
+}
+
+} // vkt
+
+namespace opt
+{
+
+DE_DECLARE_COMMAND_LINE_OPT(DstPath,	std::string);
+DE_DECLARE_COMMAND_LINE_OPT(Mode,		vkt::BuildMode);
+DE_DECLARE_COMMAND_LINE_OPT(Verbose,	bool);
+DE_DECLARE_COMMAND_LINE_OPT(Cases,		std::string);
+
+} // opt
+
+void registerOptions (de::cmdline::Parser& parser)
+{
+	using de::cmdline::Option;
+	using de::cmdline::NamedValue;
+
+	static const NamedValue<vkt::BuildMode> s_modes[] =
+	{
+		{ "build",	vkt::BUILDMODE_BUILD	},
+		{ "verify",	vkt::BUILDMODE_VERIFY	}
+	};
+
+	parser << Option<opt::DstPath>	("d", "dst-path",	"Destination path",	"out")
+		   << Option<opt::Mode>		("m", "mode",		"Build mode",		s_modes,	"build")
+		   << Option<opt::Verbose>	("v", "verbose",	"Verbose output")
+		   << Option<opt::Cases>	("n", "deqp-case",	"Case path filter (works as in test binaries)");
+}
+
+int main (int argc, const char* argv[])
+{
+	de::cmdline::CommandLine	cmdLine;
+	tcu::CommandLine			deqpCmdLine;
+
+	{
+		de::cmdline::Parser		parser;
+		registerOptions(parser);
+		if (!parser.parse(argc, argv, &cmdLine, std::cerr))
+		{
+			parser.help(std::cout);
+			return -1;
+		}
+	}
+
+	{
+		vector<const char*> deqpArgv;
+
+		deqpArgv.push_back("unused");
+
+		if (cmdLine.hasOption<opt::Cases>())
+		{
+			deqpArgv.push_back("--deqp-case");
+			deqpArgv.push_back(cmdLine.getOption<opt::Cases>().c_str());
+		}
+
+		if (!deqpCmdLine.parse((int)deqpArgv.size(), &deqpArgv[0]))
+			return -1;
+	}
+
+	try
+	{
+		tcu::DirArchive			archive			(".");
+		tcu::TestLog			log				(deqpCmdLine.getLogFileName(), deqpCmdLine.getLogFlags());
+		tcu::Platform			platform;
+		tcu::TestContext		testCtx			(platform, archive, log, deqpCmdLine, DE_NULL);
+
+		const vkt::BuildStats	stats			= vkt::buildPrograms(testCtx,
+																	 cmdLine.getOption<opt::DstPath>(),
+																	 cmdLine.getOption<opt::Mode>(),
+																	 cmdLine.getOption<opt::Verbose>());
+
+		tcu::print("DONE: %d passed, %d failed\n", stats.numSucceeded, stats.numFailed);
+
+		return stats.numFailed == 0 ? 0 : -1;
+	}
+	catch (const std::exception& e)
+	{
+		tcu::die("%s", e.what());
+	}
+}
diff --git a/external/vulkancts/modules/vulkan/vktInfo.cpp b/external/vulkancts/modules/vulkan/vktInfo.cpp
new file mode 100644
index 0000000..0d3c05e
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktInfo.cpp
@@ -0,0 +1,241 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Platform information tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktInfo.hpp"
+
+#include "vktTestCaseUtil.hpp"
+
+#include "vkPlatform.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRef.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deMemory.h"
+
+namespace vkt
+{
+namespace
+{
+
+using namespace vk;
+using std::vector;
+using std::string;
+using tcu::TestLog;
+using tcu::ScopedLogSection;
+
+tcu::TestStatus enumeratePhysicalDevices (Context& context)
+{
+	TestLog&						log		= context.getTestContext().getLog();
+	const vector<VkPhysicalDevice>	devices	= enumeratePhysicalDevices(context.getInstanceInterface(), context.getInstance());
+
+	log << TestLog::Integer("NumDevices", "Number of devices", "", QP_KEY_TAG_NONE, deInt64(devices.size()));
+
+	for (size_t ndx = 0; ndx < devices.size(); ndx++)
+		log << TestLog::Message << ndx << ": " << devices[ndx] << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Enumerating devices succeeded");
+}
+
+tcu::TestStatus enumerateInstanceLayers (Context& context)
+{
+	TestLog&						log			= context.getTestContext().getLog();
+	const vector<VkLayerProperties>	properties	= enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+	for (size_t ndx = 0; ndx < properties.size(); ndx++)
+		log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateInstanceExtensions (Context& context)
+{
+	TestLog&	log		= context.getTestContext().getLog();
+
+	{
+		const ScopedLogSection				section		(log, "Global", "Global Extensions");
+		const vector<VkExtensionProperties>	properties	= enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL);
+
+		for (size_t ndx = 0; ndx < properties.size(); ndx++)
+			log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+	}
+
+	{
+		const vector<VkLayerProperties>	layers	= enumerateInstanceLayerProperties(context.getPlatformInterface());
+
+		for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+		{
+			const ScopedLogSection				section		(log, layer->layerName, string("Layer: ") + layer->layerName);
+			const vector<VkExtensionProperties>	properties	= enumerateInstanceExtensionProperties(context.getPlatformInterface(), layer->layerName);
+
+			for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+				log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+		}
+	}
+
+	return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus enumerateDeviceLayers (Context& context)
+{
+	TestLog&						log			= context.getTestContext().getLog();
+	const vector<VkLayerProperties>	properties	= vk::enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+	for (size_t ndx = 0; ndx < properties.size(); ndx++)
+		log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Enumerating layers succeeded");
+}
+
+tcu::TestStatus enumerateDeviceExtensions (Context& context)
+{
+	TestLog&	log		= context.getTestContext().getLog();
+
+	{
+		const ScopedLogSection				section		(log, "Global", "Global Extensions");
+		const vector<VkExtensionProperties>	properties	= enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), DE_NULL);
+
+		for (size_t ndx = 0; ndx < properties.size(); ndx++)
+			log << TestLog::Message << ndx << ": " << properties[ndx] << TestLog::EndMessage;
+	}
+
+	{
+		const vector<VkLayerProperties>	layers	= enumerateDeviceLayerProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+		for (vector<VkLayerProperties>::const_iterator layer = layers.begin(); layer != layers.end(); ++layer)
+		{
+			const ScopedLogSection				section		(log, layer->layerName, string("Layer: ") + layer->layerName);
+			const vector<VkExtensionProperties>	properties	= enumerateDeviceExtensionProperties(context.getInstanceInterface(), context.getPhysicalDevice(), layer->layerName);
+
+			for (size_t extNdx = 0; extNdx < properties.size(); extNdx++)
+				log << TestLog::Message << extNdx << ": " << properties[extNdx] << TestLog::EndMessage;
+		}
+	}
+
+	return tcu::TestStatus::pass("Enumerating extensions succeeded");
+}
+
+tcu::TestStatus deviceFeatures (Context& context)
+{
+	TestLog&						log			= context.getTestContext().getLog();
+	VkPhysicalDeviceFeatures		features;
+
+	deMemset(&features, 0, sizeof(features));
+
+	VK_CHECK(context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features));
+
+	log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+		<< TestLog::Message << features << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Query succeeded");
+}
+
+tcu::TestStatus deviceProperties (Context& context)
+{
+	TestLog&						log			= context.getTestContext().getLog();
+	VkPhysicalDeviceProperties		props;
+
+	deMemset(&props, 0, sizeof(props));
+
+	VK_CHECK(context.getInstanceInterface().getPhysicalDeviceProperties(context.getPhysicalDevice(), &props));
+
+	log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage
+		<< TestLog::Message << props << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Query succeeded");
+}
+
+tcu::TestStatus deviceQueueFamilyProperties (Context& context)
+{
+	TestLog&								log					= context.getTestContext().getLog();
+	const vector<VkQueueFamilyProperties>	queueProperties		= getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+	log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
+
+	for (size_t queueNdx = 0; queueNdx < queueProperties.size(); queueNdx++)
+		log << TestLog::Message << queueNdx << ": " << queueProperties[queueNdx] << TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Querying queue properties succeeded");
+}
+
+tcu::TestStatus deviceMemoryProperties (Context& context)
+{
+	TestLog&	log		= context.getTestContext().getLog();
+
+	log << TestLog::Message << "device = " << context.getPhysicalDevice() << TestLog::EndMessage;
+
+	log << TestLog::Message
+		<< getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())
+		<< TestLog::EndMessage;
+
+	return tcu::TestStatus::pass("Querying memory properties succeeded");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createInfoTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	infoTests	(new tcu::TestCaseGroup(testCtx, "info", "Platform Information Tests"));
+
+	{
+		de::MovePtr<tcu::TestCaseGroup> instanceInfoTests	(new tcu::TestCaseGroup(testCtx, "instance", "Instance Information Tests"));
+
+		addFunctionCase(instanceInfoTests.get(), "physical_devices",		"Physical devices",			enumeratePhysicalDevices);
+		addFunctionCase(instanceInfoTests.get(), "layers",					"Layers",					enumerateInstanceLayers);
+		addFunctionCase(instanceInfoTests.get(), "extensions",				"Extensions",				enumerateInstanceExtensions);
+
+		infoTests->addChild(instanceInfoTests.release());
+	}
+
+	{
+		de::MovePtr<tcu::TestCaseGroup> deviceInfoTests	(new tcu::TestCaseGroup(testCtx, "device", "Device Information Tests"));
+
+		addFunctionCase(deviceInfoTests.get(), "features",					"Device Features",			deviceFeatures);
+		addFunctionCase(deviceInfoTests.get(), "properties",				"Device Properties",		deviceProperties);
+		addFunctionCase(deviceInfoTests.get(), "queue_family_properties",	"Queue family properties",	deviceQueueFamilyProperties);
+		addFunctionCase(deviceInfoTests.get(), "memory_properties",			"Memory properties",		deviceMemoryProperties);
+		addFunctionCase(deviceInfoTests.get(), "layers",					"Layers",					enumerateDeviceLayers);
+		addFunctionCase(deviceInfoTests.get(), "extensions",				"Extensions",				enumerateDeviceExtensions);
+
+		infoTests->addChild(deviceInfoTests.release());
+	}
+
+	return infoTests.release();
+}
+
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/vktInfo.hpp b/external/vulkancts/modules/vulkan/vktInfo.hpp
new file mode 100644
index 0000000..c2ba8d5
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktInfo.hpp
@@ -0,0 +1,47 @@
+#ifndef _VKTINFO_HPP
+#define _VKTINFO_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Platform information tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+
+tcu::TestCaseGroup*		createInfoTests		(tcu::TestContext& testCtx);
+
+} // vkt
+
+#endif // _VKTINFO_HPP
diff --git a/external/vulkancts/modules/vulkan/vktRenderPassTests.cpp b/external/vulkancts/modules/vulkan/vktRenderPassTests.cpp
new file mode 100644
index 0000000..6a0a3d0
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktRenderPassTests.cpp
@@ -0,0 +1,4483 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief RenderPass tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktRenderPassTests.hpp"
+
+#include "vktTestCaseUtil.hpp"
+
+#include "vkDefs.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkStrUtil.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuResultCollector.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuFloat.hpp"
+#include "tcuMaybe.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "deUniquePtr.hpp"
+#include "deSharedPtr.hpp"
+#include "deStringUtil.hpp"
+#include "deSTLUtil.hpp"
+#include "deRandom.hpp"
+
+#include <limits>
+
+using namespace vk;
+
+using tcu::Maybe;
+using tcu::nothing;
+using tcu::just;
+using tcu::TestLog;
+using tcu::Vec2;
+using tcu::IVec2;
+using tcu::UVec2;
+using tcu::IVec4;
+using tcu::UVec4;
+using tcu::Vec4;
+using tcu::BVec4;
+using tcu::ConstPixelBufferAccess;
+using tcu::PixelBufferAccess;
+
+using de::UniquePtr;
+
+using std::vector;
+using std::string;
+
+namespace vkt
+{
+namespace
+{
+enum
+{
+	STENCIL_VALUE = 84u,
+	// Limit integer values that are representable as floats
+	MAX_INTEGER_VALUE = ((1u<<22u)-1u)
+};
+
+// Utility functions using flattened structs
+Move<VkFence> createFence (const DeviceInterface& vk, VkDevice device, VkFenceCreateFlags flags)
+{
+	VkFence object = 0;
+	const VkFenceCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+		DE_NULL,
+
+		flags
+	};
+	VK_CHECK(vk.createFence(device, &pCreateInfo, &object));
+	return Move<VkFence>(check<VkFence>(object), Deleter<VkFence>(vk, device));
+}
+
+Move<VkRenderPass> createRenderPass (const DeviceInterface& vk, VkDevice device, deUint32 pCreateInfo_attachmentCount, const VkAttachmentDescription* pCreateInfo_pAttachments, deUint32 pCreateInfo_subpassCount, const VkSubpassDescription* pCreateInfo_pSubpasses, deUint32 pCreateInfo_dependencyCount, const VkSubpassDependency* pCreateInfo_pDependencies)
+{
+	VkRenderPass object = 0;
+	const VkRenderPassCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_attachmentCount,
+		pCreateInfo_pAttachments,
+		pCreateInfo_subpassCount,
+		pCreateInfo_pSubpasses,
+		pCreateInfo_dependencyCount,
+		pCreateInfo_pDependencies,
+	};
+	VK_CHECK(vk.createRenderPass(device, &pCreateInfo, &object));
+	return Move<VkRenderPass>(check<VkRenderPass>(object), Deleter<VkRenderPass>(vk, device));
+}
+
+Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vk, VkDevice device, VkRenderPass pCreateInfo_renderPass, deUint32 pCreateInfo_attachmentCount, const VkImageView* pCreateInfo_pAttachments, deUint32 pCreateInfo_width, deUint32 pCreateInfo_height, deUint32 pCreateInfo_layers)
+{
+	VkFramebuffer object = 0;
+	const VkFramebufferCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_renderPass,
+		pCreateInfo_attachmentCount,
+		pCreateInfo_pAttachments,
+		pCreateInfo_width,
+		pCreateInfo_height,
+		pCreateInfo_layers,
+	};
+	VK_CHECK(vk.createFramebuffer(device, &pCreateInfo, &object));
+	return Move<VkFramebuffer>(check<VkFramebuffer>(object), Deleter<VkFramebuffer>(vk, device));
+}
+
+Move<VkImage> createImage (const DeviceInterface& vk, VkDevice device, VkImageType pCreateInfo_imageType, VkFormat pCreateInfo_format, VkExtent3D pCreateInfo_extent, deUint32 pCreateInfo_mipLevels, deUint32 pCreateInfo_arraySize, deUint32 pCreateInfo_samples, VkImageTiling pCreateInfo_tiling, VkImageUsageFlags pCreateInfo_usage, VkImageCreateFlags pCreateInfo_flags, VkSharingMode pCreateInfo_sharingMode, deUint32 pCreateInfo_queueFamilyCount, const deUint32* pCreateInfo_pQueueFamilyIndices, VkImageLayout pCreateInfo_initialLayout)
+{
+	VkImage object = 0;
+	const VkImageCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_imageType,
+		pCreateInfo_format,
+		pCreateInfo_extent,
+		pCreateInfo_mipLevels,
+		pCreateInfo_arraySize,
+		pCreateInfo_samples,
+		pCreateInfo_tiling,
+		pCreateInfo_usage,
+		pCreateInfo_flags,
+		pCreateInfo_sharingMode,
+		pCreateInfo_queueFamilyCount,
+		pCreateInfo_pQueueFamilyIndices,
+		pCreateInfo_initialLayout
+	};
+	VK_CHECK(vk.createImage(device, &pCreateInfo, &object));
+	return Move<VkImage>(check<VkImage>(object), Deleter<VkImage>(vk, device));
+}
+
+void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset)
+{
+	VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset));
+}
+
+void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset)
+{
+	VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset));
+}
+
+Move<VkImageView> createImageView (const DeviceInterface&	vk,
+									VkDevice				device,
+									VkImage					pCreateInfo_image,
+									VkImageViewType			pCreateInfo_viewType,
+									VkFormat				pCreateInfo_format,
+									VkChannelMapping		pCreateInfo_channels,
+									VkImageSubresourceRange	pCreateInfo_subresourceRange,
+									VkImageViewCreateFlags	pCreateInfo_flags)
+{
+	VkImageView object = 0;
+	const VkImageViewCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_image,
+		pCreateInfo_viewType,
+		pCreateInfo_format,
+		pCreateInfo_channels,
+		pCreateInfo_subresourceRange,
+		pCreateInfo_flags,
+	};
+	VK_CHECK(vk.createImageView(device, &pCreateInfo, &object));
+	return Move<VkImageView>(check<VkImageView>(object), Deleter<VkImageView>(vk, device));
+}
+
+Move<VkBuffer> createBuffer (const DeviceInterface& vk, VkDevice device, VkDeviceSize pCreateInfo_size, VkBufferUsageFlags pCreateInfo_usage, VkBufferCreateFlags pCreateInfo_flags, VkSharingMode pCreateInfo_sharingMode, deUint32 pCreateInfo_queueFamilyCount, const deUint32* pCreateInfo_pQueueFamilyIndices)
+{
+	VkBuffer object = 0;
+	const VkBufferCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_size,
+		pCreateInfo_usage,
+		pCreateInfo_flags,
+		pCreateInfo_sharingMode,
+		pCreateInfo_queueFamilyCount,
+		pCreateInfo_pQueueFamilyIndices,
+	};
+	VK_CHECK(vk.createBuffer(device, &pCreateInfo, &object));
+	return Move<VkBuffer>(check<VkBuffer>(object), Deleter<VkBuffer>(vk, device));
+}
+
+Move<VkShader> createShader (const DeviceInterface& vk, VkDevice device, VkShaderModule pCreateInfo_module, const char* pCreateInfo_pName, VkShaderCreateFlags pCreateInfo_flags, VkShaderStage pCreateInfo_stage)
+{
+	VkShader object = 0;
+	const VkShaderCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_module,
+		pCreateInfo_pName,
+		pCreateInfo_flags,
+		pCreateInfo_stage,
+	};
+	VK_CHECK(vk.createShader(device, &pCreateInfo, &object));
+	return Move<VkShader>(check<VkShader>(object), Deleter<VkShader>(vk, device));
+}
+
+Move<VkCmdPool> createCommandPool (const DeviceInterface& vk, VkDevice device, deUint32 pCreateInfo_queueFamilyIndex, VkCmdPoolCreateFlags pCreateInfo_flags)
+{
+	VkCmdPool object = 0;
+	const VkCmdPoolCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_queueFamilyIndex,
+		pCreateInfo_flags,
+	};
+	VK_CHECK(vk.createCommandPool(device, &pCreateInfo, &object));
+	return Move<VkCmdPool>(check<VkCmdPool>(object), Deleter<VkCmdPool>(vk, device));
+}
+
+void cmdBeginRenderPass (const DeviceInterface& vk, VkCmdBuffer cmdBuffer, VkRenderPass pRenderPassBegin_renderPass, VkFramebuffer pRenderPassBegin_framebuffer, VkRect2D pRenderPassBegin_renderArea, deUint32 pRenderPassBegin_attachmentCount, const VkClearValue* pRenderPassBegin_pAttachmentClearValues, VkRenderPassContents contents)
+{
+	const VkRenderPassBeginInfo pRenderPassBegin =
+	{
+		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+		DE_NULL,
+		pRenderPassBegin_renderPass,
+		pRenderPassBegin_framebuffer,
+		pRenderPassBegin_renderArea,
+		pRenderPassBegin_attachmentCount,
+		pRenderPassBegin_pAttachmentClearValues,
+	};
+	vk.cmdBeginRenderPass(cmdBuffer, &pRenderPassBegin, contents);
+}
+
+Move<VkCmdBuffer> createCommandBuffer (const DeviceInterface& vk, VkDevice device, VkCmdPool pCreateInfo_cmdPool, VkCmdBufferLevel pCreateInfo_level, VkCmdBufferCreateFlags pCreateInfo_flags)
+{
+	VkCmdBuffer object = 0;
+	const VkCmdBufferCreateInfo pCreateInfo =
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
+		DE_NULL,
+		pCreateInfo_cmdPool,
+		pCreateInfo_level,
+		pCreateInfo_flags,
+	};
+	VK_CHECK(vk.createCommandBuffer(device, &pCreateInfo, &object));
+	return Move<VkCmdBuffer>(check<VkCmdBuffer>(object), Deleter<VkCmdBuffer>(vk, device));
+}
+
+void beginCommandBuffer (const DeviceInterface& vk, VkCmdBuffer cmdBuffer, VkCmdBufferOptimizeFlags pBeginInfo_flags, VkRenderPass pBeginInfo_renderPass, deUint32 pBeginInfo_subpass, VkFramebuffer pBeginInfo_framebuffer)
+{
+	const VkCmdBufferBeginInfo pBeginInfo =
+	{
+		VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
+		DE_NULL,
+		pBeginInfo_flags,
+		pBeginInfo_renderPass,
+		pBeginInfo_subpass,
+		pBeginInfo_framebuffer,
+	};
+	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &pBeginInfo));
+}
+
+void endCommandBuffer (const DeviceInterface& vk, VkCmdBuffer cmdBuffer)
+{
+	VK_CHECK(vk.endCommandBuffer(cmdBuffer));
+}
+
+void queueSubmit (const DeviceInterface& vk, VkQueue queue, deUint32 cmdBufferCount, const VkCmdBuffer* pCmdBuffers, VkFence fence)
+{
+	VK_CHECK(vk.queueSubmit(queue, cmdBufferCount, pCmdBuffers, fence));
+}
+
+void waitForFences (const DeviceInterface& vk, VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout)
+{
+	VK_CHECK(vk.waitForFences(device, fenceCount, pFences, waitAll, timeout));
+}
+
+VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat)
+{
+	const tcu::TextureFormat format = mapVkFormat(vkFormat);
+
+	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
+
+	switch (format.order)
+	{
+		case tcu::TextureFormat::DS:
+			return VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
+
+		case tcu::TextureFormat::D:
+			return VK_IMAGE_ASPECT_DEPTH_BIT;
+
+		case tcu::TextureFormat::S:
+			return VK_IMAGE_ASPECT_STENCIL_BIT;
+
+		default:
+			return VK_IMAGE_ASPECT_COLOR_BIT;
+	}
+}
+
+VkMemoryInputFlags getAllMemoryInputFlags (void)
+{
+	return VK_MEMORY_INPUT_TRANSFER_BIT
+		   | VK_MEMORY_INPUT_UNIFORM_READ_BIT
+		   | VK_MEMORY_INPUT_HOST_READ_BIT
+		   | VK_MEMORY_INPUT_INDEX_FETCH_BIT
+		   | VK_MEMORY_INPUT_SHADER_READ_BIT
+		   | VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT
+		   | VK_MEMORY_INPUT_INDIRECT_COMMAND_BIT
+		   | VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT
+		   | VK_MEMORY_INPUT_INPUT_ATTACHMENT_BIT
+		   | VK_MEMORY_INPUT_DEPTH_STENCIL_ATTACHMENT_BIT;
+}
+
+VkMemoryOutputFlags getAllMemoryOutputFlags (void)
+{
+	return VK_MEMORY_OUTPUT_TRANSFER_BIT
+		   | VK_MEMORY_OUTPUT_HOST_WRITE_BIT
+		   | VK_MEMORY_OUTPUT_SHADER_WRITE_BIT
+		   | VK_MEMORY_OUTPUT_DEPTH_STENCIL_ATTACHMENT_BIT
+		   | VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT;
+}
+
+VkPipelineStageFlags getAllPipelineStageFlags (void)
+{
+	return VK_PIPELINE_STAGE_TESS_EVALUATION_SHADER_BIT
+		   | VK_PIPELINE_STAGE_TRANSFER_BIT
+		   | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
+		   | VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
+		   | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
+		   | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
+		   | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
+		   | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+		   | VK_PIPELINE_STAGE_TESS_CONTROL_SHADER_BIT
+		   | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+		   | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
+		   | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+		   | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+}
+
+class AttachmentReference
+{
+public:
+					AttachmentReference		(deUint32		attachment,
+											 VkImageLayout	layout)
+		: m_attachment	(attachment)
+		, m_layout		(layout)
+	{
+	}
+
+	deUint32		getAttachment			(void) const { return m_attachment;	}
+	VkImageLayout	getImageLayout			(void) const { return m_layout;		}
+
+private:
+	deUint32		m_attachment;
+	VkImageLayout	m_layout;
+};
+
+class Subpass
+{
+public:
+										Subpass						(VkPipelineBindPoint				pipelineBindPoint,
+																	 VkSubpassDescriptionFlags			flags,
+																	 const vector<AttachmentReference>&	inputAttachments,
+																	 const vector<AttachmentReference>&	colorAttachments,
+																	 const vector<AttachmentReference>&	resolveAttachments,
+																	 AttachmentReference				depthStencilAttachment,
+																	 const vector<AttachmentReference>&	preserveAttachments)
+		: m_pipelineBindPoint		(pipelineBindPoint)
+		, m_flags					(flags)
+		, m_inputAttachments		(inputAttachments)
+		, m_colorAttachments		(colorAttachments)
+		, m_resolveAttachments		(resolveAttachments)
+		, m_depthStencilAttachment	(depthStencilAttachment)
+		, m_preserveAttachments		(preserveAttachments)
+	{
+	}
+
+	VkPipelineBindPoint					getPipelineBindPoint		(void) const { return m_pipelineBindPoint;		}
+	VkSubpassDescriptionFlags			getFlags					(void) const { return m_flags;					}
+	const vector<AttachmentReference>&	getInputAttachments			(void) const { return m_inputAttachments;		}
+	const vector<AttachmentReference>&	getColorAttachments			(void) const { return m_colorAttachments;		}
+	const vector<AttachmentReference>&	getResolveAttachments		(void) const { return m_resolveAttachments;		}
+	const AttachmentReference&			getDepthStencilAttachment	(void) const { return m_depthStencilAttachment;	}
+	const vector<AttachmentReference>&	getPreserveAttachments		(void) const { return m_preserveAttachments;	}
+
+private:
+	VkPipelineBindPoint					m_pipelineBindPoint;
+	VkSubpassDescriptionFlags			m_flags;
+
+	vector<AttachmentReference>			m_inputAttachments;
+	vector<AttachmentReference>			m_colorAttachments;
+	vector<AttachmentReference>			m_resolveAttachments;
+	AttachmentReference					m_depthStencilAttachment;
+
+	vector<AttachmentReference>			m_preserveAttachments;
+};
+
+class SubpassDependency
+{
+public:
+							SubpassDependency	(deUint32				srcPass,
+												 deUint32				dstPass,
+
+												 VkPipelineStageFlags	srcStageMask,
+												 VkPipelineStageFlags	dstStageMask,
+
+												 VkMemoryOutputFlags	outputMask,
+												 VkMemoryInputFlags		inputMask,
+
+												 VkBool32				byRegion)
+		: m_srcPass			(srcPass)
+		, m_dstPass			(dstPass)
+
+		, m_srcStageMask	(srcStageMask)
+		, m_dstStageMask	(dstStageMask)
+
+		, m_outputMask		(outputMask)
+		, m_inputMask		(inputMask)
+		, m_byRegion		(byRegion)
+	{
+	}
+
+	deUint32				getSrcPass			(void) const { return m_srcPass;		}
+	deUint32				getDstPass			(void) const { return m_dstPass;		}
+
+	VkPipelineStageFlags	getSrcStageMask		(void) const { return m_srcStageMask;	}
+	VkPipelineStageFlags	getDstStageMask		(void) const { return m_dstStageMask;	}
+
+	VkMemoryOutputFlags		getOutputMask		(void) const { return m_outputMask;		}
+	VkMemoryInputFlags		getInputMask		(void) const { return m_inputMask;		}
+
+	VkBool32				getByRegion			(void) const { return m_byRegion;		}
+
+private:
+	deUint32				m_srcPass;
+	deUint32				m_dstPass;
+
+	VkPipelineStageFlags	m_srcStageMask;
+	VkPipelineStageFlags	m_dstStageMask;
+
+	VkMemoryOutputFlags		m_outputMask;
+	VkMemoryInputFlags		m_inputMask;
+	VkBool32				m_byRegion;
+};
+
+class Attachment
+{
+public:
+						Attachment			(VkFormat				format,
+											 deUint32				samples,
+
+											 VkAttachmentLoadOp		loadOp,
+											 VkAttachmentStoreOp	storeOp,
+
+											 VkAttachmentLoadOp		stencilLoadOp,
+											 VkAttachmentStoreOp	stencilStoreOp,
+
+											 VkImageLayout			initialLayout,
+											 VkImageLayout			finalLayout)
+		: m_format			(format)
+		, m_samples			(samples)
+
+		, m_loadOp			(loadOp)
+		, m_storeOp			(storeOp)
+
+		, m_stencilLoadOp	(stencilLoadOp)
+		, m_stencilStoreOp	(stencilStoreOp)
+
+		, m_initialLayout	(initialLayout)
+		, m_finalLayout		(finalLayout)
+	{
+	}
+
+	VkFormat			getFormat			(void) const { return m_format;			}
+	deUint32			getSamples			(void) const { return m_samples;		}
+
+	VkAttachmentLoadOp	getLoadOp			(void) const { return m_loadOp;			}
+	VkAttachmentStoreOp	getStoreOp			(void) const { return m_storeOp;		}
+
+
+	VkAttachmentLoadOp	getStencilLoadOp	(void) const { return m_stencilLoadOp;	}
+	VkAttachmentStoreOp	getStencilStoreOp	(void) const { return m_stencilStoreOp;	}
+
+	VkImageLayout		getInitialLayout	(void) const { return m_initialLayout;	}
+	VkImageLayout		getFinalLayout		(void) const { return m_finalLayout;	}
+
+private:
+	VkFormat			m_format;
+	deUint32			m_samples;
+
+	VkAttachmentLoadOp	m_loadOp;
+	VkAttachmentStoreOp	m_storeOp;
+
+	VkAttachmentLoadOp	m_stencilLoadOp;
+	VkAttachmentStoreOp	m_stencilStoreOp;
+
+	VkImageLayout		m_initialLayout;
+	VkImageLayout		m_finalLayout;
+};
+
+class RenderPass
+{
+public:
+										RenderPass		(const vector<Attachment>&			attachments,
+														 const vector<Subpass>&				subpasses,
+														 const vector<SubpassDependency>&	dependencies)
+		: m_attachments		(attachments)
+		, m_subpasses		(subpasses)
+		, m_dependencies	(dependencies)
+	{
+	}
+
+	const vector<Attachment>&			getAttachments	(void) const { return m_attachments;	}
+	const vector<Subpass>&				getSubpasses	(void) const { return m_subpasses;		}
+	const vector<SubpassDependency>&	getDependencies	(void) const { return m_dependencies;	}
+
+private:
+	const vector<Attachment>			m_attachments;
+	const vector<Subpass>				m_subpasses;
+	const vector<SubpassDependency>		m_dependencies;
+};
+
+struct TestConfig
+{
+	enum RenderTypes
+	{
+		RENDERTYPES_NONE	= 0,
+		RENDERTYPES_CLEAR	= (1<<1),
+		RENDERTYPES_DRAW	= (1<<2)
+	};
+
+	enum CommandBufferTypes
+	{
+		COMMANDBUFFERTYPES_INLINE		= (1<<0),
+		COMMANDBUFFERTYPES_SECONDARY	= (1<<1)
+	};
+
+	enum ImageMemory
+	{
+		IMAGEMEMORY_STRICT		= (1<<0),
+		IMAGEMEMORY_LAZY		= (1<<1)
+	};
+
+	TestConfig (const RenderPass&	renderPass_,
+				RenderTypes			renderTypes_,
+				CommandBufferTypes	commandBufferTypes_,
+				ImageMemory			imageMemory_,
+				const UVec2&		targetSize_,
+				const UVec2&		renderPos_,
+				const UVec2&		renderSize_,
+				deUint32			seed_)
+		: renderPass			(renderPass_)
+		, renderTypes			(renderTypes_)
+		, commandBufferTypes	(commandBufferTypes_)
+		, imageMemory			(imageMemory_)
+		, targetSize			(targetSize_)
+		, renderPos				(renderPos_)
+		, renderSize			(renderSize_)
+		, seed					(seed_)
+	{
+	}
+
+	RenderPass			renderPass;
+	RenderTypes			renderTypes;
+	CommandBufferTypes	commandBufferTypes;
+	ImageMemory			imageMemory;
+	UVec2				targetSize;
+	UVec2				renderPos;
+	UVec2				renderSize;
+	deUint32			seed;
+};
+
+TestConfig::RenderTypes operator| (TestConfig::RenderTypes a, TestConfig::RenderTypes b)
+{
+	return (TestConfig::RenderTypes)(((deUint32)a) | ((deUint32)b));
+}
+
+TestConfig::CommandBufferTypes operator| (TestConfig::CommandBufferTypes a, TestConfig::CommandBufferTypes b)
+{
+	return (TestConfig::CommandBufferTypes)(((deUint32)a) | ((deUint32)b));
+}
+
+TestConfig::ImageMemory operator| (TestConfig::ImageMemory a, TestConfig::ImageMemory b)
+{
+	return (TestConfig::ImageMemory)(((deUint32)a) | ((deUint32)b));
+}
+
+void logRenderPassInfo (TestLog&			log,
+						const RenderPass&	renderPass)
+{
+	const tcu::ScopedLogSection section (log, "RenderPass", "RenderPass");
+
+	{
+		const tcu::ScopedLogSection	attachmentsSection	(log, "Attachments", "Attachments");
+		const vector<Attachment>&	attachments			= renderPass.getAttachments();
+
+		for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
+		{
+			const tcu::ScopedLogSection	attachmentSection	(log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
+			const Attachment&			attachment			= attachments[attachmentNdx];
+
+			log << TestLog::Message << "Format: " << attachment.getFormat() << TestLog::EndMessage;
+			log << TestLog::Message << "Samples: " << attachment.getSamples() << TestLog::EndMessage;
+
+			log << TestLog::Message << "LoadOp: " << attachment.getLoadOp() << TestLog::EndMessage;
+			log << TestLog::Message << "StoreOp: " << attachment.getStoreOp() << TestLog::EndMessage;
+
+			log << TestLog::Message << "StencilLoadOp: " << attachment.getStencilLoadOp() << TestLog::EndMessage;
+			log << TestLog::Message << "StencilStoreOp: " << attachment.getStencilStoreOp() << TestLog::EndMessage;
+
+			log << TestLog::Message << "InitialLayout: " << attachment.getInitialLayout() << TestLog::EndMessage;
+			log << TestLog::Message << "FinalLayout: " << attachment.getFinalLayout() << TestLog::EndMessage;
+		}
+	}
+
+	{
+		const tcu::ScopedLogSection	subpassesSection	(log, "Subpasses", "Subpasses");
+		const vector<Subpass>&		subpasses			= renderPass.getSubpasses();
+
+		for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
+		{
+			const tcu::ScopedLogSection			subpassSection		(log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
+			const Subpass&						subpass				= subpasses[subpassNdx];
+
+			const vector<AttachmentReference>&	inputAttachments	= subpass.getInputAttachments();
+			const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
+			const vector<AttachmentReference>&	resolveAttachments	= subpass.getResolveAttachments();
+			const vector<AttachmentReference>&	preserveAttachments	= subpass.getPreserveAttachments();
+
+			if (!inputAttachments.empty())
+			{
+				const tcu::ScopedLogSection		inputAttachmentsSection	(log, "Inputs", "Inputs");
+
+				for (size_t inputNdx = 0; inputNdx < inputAttachments.size(); inputNdx++)
+				{
+					const tcu::ScopedLogSection		inputAttachmentSection	(log, "Input" + de::toString(inputNdx), "Input " + de::toString(inputNdx));
+					const AttachmentReference&		inputAttachment			= inputAttachments[inputNdx];
+
+					log << TestLog::Message << "Attachment: " << inputAttachment.getAttachment() << TestLog::EndMessage;
+					log << TestLog::Message << "Layout: " << inputAttachment.getImageLayout() << TestLog::EndMessage;
+				}
+			}
+
+			if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
+			{
+				const tcu::ScopedLogSection		depthStencilAttachmentSection	(log, "DepthStencil", "DepthStencil");
+				const AttachmentReference&		depthStencilAttachment			= subpass.getDepthStencilAttachment();
+
+				log << TestLog::Message << "Attachment: " << depthStencilAttachment.getAttachment() << TestLog::EndMessage;
+				log << TestLog::Message << "Layout: " << depthStencilAttachment.getImageLayout() << TestLog::EndMessage;
+			}
+
+			if (!colorAttachments.empty())
+			{
+				const tcu::ScopedLogSection		colorAttachmentsSection	(log, "Colors", "Colors");
+
+				for (size_t colorNdx = 0; colorNdx < colorAttachments.size(); colorNdx++)
+				{
+					const tcu::ScopedLogSection		colorAttachmentSection	(log, "Color" + de::toString(colorNdx), "Color " + de::toString(colorNdx));
+					const AttachmentReference&		colorAttachment			= colorAttachments[colorNdx];
+
+					log << TestLog::Message << "Attachment: " << colorAttachment.getAttachment() << TestLog::EndMessage;
+					log << TestLog::Message << "Layout: " << colorAttachment.getImageLayout() << TestLog::EndMessage;
+				}
+			}
+
+			if (!resolveAttachments.empty())
+			{
+				const tcu::ScopedLogSection		resolveAttachmentsSection	(log, "Resolves", "Resolves");
+
+				for (size_t resolveNdx = 0; resolveNdx < resolveAttachments.size(); resolveNdx++)
+				{
+					const tcu::ScopedLogSection		resolveAttachmentSection	(log, "Resolve" + de::toString(resolveNdx), "Resolve " + de::toString(resolveNdx));
+					const AttachmentReference&		resolveAttachment			= resolveAttachments[resolveNdx];
+
+					log << TestLog::Message << "Attachment: " << resolveAttachment.getAttachment() << TestLog::EndMessage;
+					log << TestLog::Message << "Layout: " << resolveAttachment.getImageLayout() << TestLog::EndMessage;
+				}
+			}
+
+			if (!preserveAttachments.empty())
+			{
+				const tcu::ScopedLogSection		preserveAttachmentsSection	(log, "Preserves", "Preserves");
+
+				for (size_t preserveNdx = 0; preserveNdx < preserveAttachments.size(); preserveNdx++)
+				{
+					const tcu::ScopedLogSection		preserveAttachmentSection	(log, "Preserve" + de::toString(preserveNdx), "Preserve " + de::toString(preserveNdx));
+					const AttachmentReference&		preserveAttachment			= preserveAttachments[preserveNdx];
+
+					log << TestLog::Message << "Attachment: " << preserveAttachment.getAttachment() << TestLog::EndMessage;
+					log << TestLog::Message << "Layout: " << preserveAttachment.getImageLayout() << TestLog::EndMessage;
+				}
+			}
+		}
+
+	}
+
+	if (!renderPass.getDependencies().empty())
+	{
+		const tcu::ScopedLogSection	dependenciesSection	(log, "Dependencies", "Dependencies");
+
+		for (size_t depNdx = 0; depNdx < renderPass.getDependencies().size(); depNdx++)
+		{
+			const tcu::ScopedLogSection	dependencySection	(log, "Dependency" + de::toString(depNdx), "Dependency " + de::toString(depNdx));
+			const SubpassDependency&	dep					= renderPass.getDependencies()[depNdx];
+
+			log << TestLog::Message << "Source: " << dep.getSrcPass() << TestLog::EndMessage;
+			log << TestLog::Message << "Destination: " << dep.getDstPass() << TestLog::EndMessage;
+
+			log << TestLog::Message << "Source Stage Mask: " << dep.getSrcStageMask() << TestLog::EndMessage;
+			log << TestLog::Message << "Destination Stage Mask: " << dep.getDstStageMask() << TestLog::EndMessage;
+
+			log << TestLog::Message << "Input Mask: " << dep.getInputMask() << TestLog::EndMessage;
+			log << TestLog::Message << "Output Mask: " << dep.getOutputMask() << TestLog::EndMessage;
+			log << TestLog::Message << "By Region: " << dep.getByRegion() << TestLog::EndMessage;
+		}
+	}
+}
+
+std::string clearColorToString (VkFormat vkFormat, VkClearColorValue value)
+{
+	const tcu::TextureFormat		format			= mapVkFormat(vkFormat);
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+	const tcu::BVec4				channelMask		= tcu::getTextureFormatChannelMask(format);
+
+	std::ostringstream				stream;
+
+	stream << "(";
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+			for (int i = 0; i < 4; i++)
+			{
+				if (i > 0)
+					stream << ", ";
+
+				if (channelMask[i])
+					stream << value.int32[i];
+				else
+					stream << "Undef";
+			}
+			break;
+
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+			for (int i = 0; i < 4; i++)
+			{
+				if (i > 0)
+					stream << ", ";
+
+				if (channelMask[i])
+					stream << value.uint32[i];
+				else
+					stream << "Undef";
+			}
+			break;
+
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+			for (int i = 0; i < 4; i++)
+			{
+				if (i > 0)
+					stream << ", ";
+
+				if (channelMask[i])
+					stream << value.float32[i];
+				else
+					stream << "Undef";
+			}
+			break;
+
+		default:
+			DE_FATAL("Unknown channel class");
+	}
+
+	stream << ")";
+
+	return stream.str();
+}
+
+std::string clearValueToString (VkFormat vkFormat, VkClearValue value)
+{
+	const tcu::TextureFormat	format	= mapVkFormat(vkFormat);
+
+	if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
+	{
+		std::ostringstream stream;
+
+		stream << "(";
+
+		if (tcu::hasStencilComponent(format.order))
+			stream << "stencil: " << value.depthStencil.stencil;
+
+		if (tcu::hasStencilComponent(format.order) && tcu::hasDepthComponent(format.order))
+			stream << ", ";
+
+		if (tcu::hasDepthComponent(format.order))
+			stream << "depth: " << value.depthStencil.depth;
+
+		stream << ")";
+
+		return stream.str();
+	}
+	else
+		return clearColorToString(vkFormat, value.color);
+}
+
+VkClearColorValue randomColorClearValue (const Attachment& attachment, de::Random& rng)
+{
+	const float						clearNan		= tcu::Float32::nan().asFloat();
+	const tcu::TextureFormat		format			= mapVkFormat(attachment.getFormat());
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+	const tcu::BVec4				channelMask		= tcu::getTextureFormatChannelMask(format);
+	VkClearColorValue				clearColor;
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+		{
+			const tcu::IVec4 valueMin = tcu::getFormatMinIntValue(format);
+			const tcu::IVec4 valueMax = tcu::getFormatMaxIntValue(format);
+
+			for (int ndx = 0; ndx < 4; ndx++)
+			{
+				if (!channelMask[ndx])
+					clearColor.int32[ndx] = std::numeric_limits<deInt32>::min();
+				else
+					clearColor.uint32[ndx] = rng.getInt(valueMin[ndx], valueMax[ndx]);
+			}
+			break;
+		}
+
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+		{
+			const UVec4 valueMax = tcu::getFormatMaxUintValue(format);
+
+			for (int ndx = 0; ndx < 4; ndx++)
+			{
+				if (!channelMask[ndx])
+					clearColor.uint32[ndx] = std::numeric_limits<deUint32>::max();
+				else
+					clearColor.uint32[ndx] = rng.getUint32() % valueMax[ndx];
+			}
+			break;
+		}
+
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+		{
+			const tcu::TextureFormatInfo	formatInfo		= tcu::getTextureFormatInfo(format);
+
+			for (int ndx = 0; ndx < 4; ndx++)
+			{
+				if (!channelMask[ndx])
+					clearColor.float32[ndx] = clearNan;
+				else
+					clearColor.float32[ndx] = formatInfo.valueMin[ndx] + rng.getFloat() * (formatInfo.valueMax[ndx] - formatInfo.valueMin[ndx]);
+			}
+			break;
+		}
+
+		default:
+			DE_FATAL("Unknown channel class");
+	}
+
+	return clearColor;
+}
+
+VkAttachmentDescription createAttachmentDescription (const Attachment& attachment)
+{
+	const VkAttachmentDescription attachmentDescription =
+	{
+		VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,	// sType;
+		DE_NULL,									// pNext;
+
+		attachment.getFormat(),						// format;
+		attachment.getSamples(),					// samples;
+
+		attachment.getLoadOp(),						// loadOp;
+		attachment.getStoreOp(),					// storeOp;
+
+		attachment.getStencilLoadOp(),				// stencilLoadOp;
+		attachment.getStencilStoreOp(),				// stencilStoreOp;
+
+		attachment.getInitialLayout(),				// initialLayout;
+		attachment.getFinalLayout(),				// finalLayout;
+
+		0											// Flags
+	};
+
+	return attachmentDescription;
+}
+
+VkAttachmentReference createAttachmentReference (const AttachmentReference& referenceInfo)
+{
+	const VkAttachmentReference reference =
+	{
+		referenceInfo.getAttachment(),	// attachment;
+		referenceInfo.getImageLayout()	// layout;
+	};
+
+	return reference;
+}
+
+VkSubpassDescription createSubpassDescription (const Subpass&					subpass,
+											   vector<VkAttachmentReference>*	attachmentReferenceLists)
+{
+	vector<VkAttachmentReference>&	inputAttachmentReferences		= attachmentReferenceLists[0];
+	vector<VkAttachmentReference>&	colorAttachmentReferences		= attachmentReferenceLists[1];
+	vector<VkAttachmentReference>&	resolveAttachmentReferences		= attachmentReferenceLists[2];
+	vector<VkAttachmentReference>&	preserveAttachmentReferences	= attachmentReferenceLists[3];
+
+	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
+		colorAttachmentReferences.push_back(createAttachmentReference(subpass.getColorAttachments()[attachmentNdx]));
+
+	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++)
+		inputAttachmentReferences.push_back(createAttachmentReference(subpass.getInputAttachments()[attachmentNdx]));
+
+	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getResolveAttachments().size(); attachmentNdx++)
+		resolveAttachmentReferences.push_back(createAttachmentReference(subpass.getResolveAttachments()[attachmentNdx]));
+
+	for (size_t attachmentNdx = 0; attachmentNdx < subpass.getPreserveAttachments().size(); attachmentNdx++)
+		preserveAttachmentReferences.push_back(createAttachmentReference(subpass.getPreserveAttachments()[attachmentNdx]));
+
+	DE_ASSERT(resolveAttachmentReferences.empty() || colorAttachmentReferences.size() == resolveAttachmentReferences.size());
+
+	{
+		const VkSubpassDescription subpasssDescription =
+		{
+			VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,												// sType;
+			DE_NULL,																			// pNext;
+
+			subpass.getPipelineBindPoint(),														// pipelineBindPoint;
+			subpass.getFlags(),																	// flags;
+
+			(deUint32)inputAttachmentReferences.size(),											// inputCount;
+			inputAttachmentReferences.empty() ? DE_NULL : &inputAttachmentReferences[0],		// inputAttachments;
+
+			(deUint32)colorAttachmentReferences.size(),											// colorCount;
+			colorAttachmentReferences.empty() ? DE_NULL :  &colorAttachmentReferences[0],		// colorAttachments;
+			resolveAttachmentReferences.empty() ? DE_NULL : &resolveAttachmentReferences[0],	// resolveAttachments;
+
+			createAttachmentReference(subpass.getDepthStencilAttachment()),						// depthStencilAttachment;
+			(deUint32)preserveAttachmentReferences.size(),										// preserveCount;
+			preserveAttachmentReferences.empty() ? DE_NULL : &preserveAttachmentReferences[0]	// preserveAttachments;
+		};
+
+		return subpasssDescription;
+	}
+}
+
+VkSubpassDependency createSubpassDependency	(const SubpassDependency& dependencyInfo)
+{
+	const VkSubpassDependency dependency =
+	{
+		VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY,	// sType;
+		DE_NULL,								// pNext;
+
+		dependencyInfo.getSrcPass(),			// srcSubpass;
+		dependencyInfo.getDstPass(),			// destSubpass;
+
+		dependencyInfo.getSrcStageMask(),		// srcStageMask;
+		dependencyInfo.getDstStageMask(),		// destStageMask;
+
+		dependencyInfo.getOutputMask(),			// outputMask;
+		dependencyInfo.getInputMask(),			// inputMask;
+
+		dependencyInfo.getByRegion()			// byRegion;
+	};
+
+	return dependency;
+}
+
+Move<VkRenderPass> createRenderPass (const DeviceInterface&	vk,
+									 VkDevice				device,
+									 const RenderPass&		renderPassInfo)
+{
+	const size_t							perSubpassAttachmentReferenceLists = 4;
+	vector<VkAttachmentDescription>			attachments;
+	vector<VkSubpassDescription>			subpasses;
+	vector<VkSubpassDependency>				dependencies;
+	vector<vector<VkAttachmentReference> >	attachmentReferenceLists(renderPassInfo.getSubpasses().size() * perSubpassAttachmentReferenceLists);
+
+	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
+		attachments.push_back(createAttachmentDescription(renderPassInfo.getAttachments()[attachmentNdx]));
+
+	for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
+		subpasses.push_back(createSubpassDescription(renderPassInfo.getSubpasses()[subpassNdx], &(attachmentReferenceLists[subpassNdx * perSubpassAttachmentReferenceLists])));
+
+	for (size_t depNdx = 0; depNdx < renderPassInfo.getDependencies().size(); depNdx++)
+		dependencies.push_back(createSubpassDependency(renderPassInfo.getDependencies()[depNdx]));
+
+	{
+		return createRenderPass(vk, device, (deUint32)attachments.size(),	(attachments.empty()	? DE_NULL : &attachments[0]),
+											(deUint32)subpasses.size(),		(subpasses.empty()		? DE_NULL : &subpasses[0]),
+											(deUint32)dependencies.size(),	(dependencies.empty()	? DE_NULL : &dependencies[0]));
+	}
+}
+
+Move<VkFramebuffer> createFramebuffer (const DeviceInterface&		vk,
+									   VkDevice						device,
+									   VkRenderPass					renderPass,
+									   const UVec2&					size,
+									   const vector<VkImageView>&	attachments)
+{
+	return createFramebuffer(vk, device, renderPass, (deUint32)attachments.size(), attachments.empty() ? DE_NULL : &attachments[0], size.x(), size.y(), 1u);
+}
+
+Move<VkImage> createAttachmentImage (const DeviceInterface&	vk,
+									 VkDevice				device,
+									 deUint32				queueIndex,
+									 const UVec2&			size,
+									 VkFormat				format,
+									 deUint32				samples,
+									 VkImageUsageFlags		usageFlags,
+									 VkImageLayout			layout)
+{
+	const VkExtent3D size_ = { (deInt32)size.x(), (deInt32)size.y(), 1 };
+	return createImage(vk, device, VK_IMAGE_TYPE_2D, format, size_, 1u /* mipLevels */, 1u /* arraySize */, samples, VK_IMAGE_TILING_OPTIMAL, usageFlags, 0u, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex, layout);
+}
+
+de::MovePtr<Allocation> createImageMemory (const DeviceInterface&	vk,
+										   VkDevice					device,
+										   Allocator&				allocator,
+										   VkImage					image,
+										   bool						lazy)
+{
+	de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), lazy ? MemoryRequirement::LazilyAllocated : MemoryRequirement::Any));
+	bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset());
+	return allocation;
+}
+
+Move<VkImageView> createImageAttachmentView (const DeviceInterface&	vk,
+											 VkDevice				device,
+											 VkImage				image,
+											 VkFormat				format,
+											 VkImageAspectFlags		aspect)
+{
+	const VkImageSubresourceRange range =
+	{
+		aspect,
+		0,
+		1,
+		0,
+		1
+	};
+
+	return createImageView(vk, device, image, VK_IMAGE_VIEW_TYPE_2D, format, makeChannelMappingRGBA(), range, 0);
+}
+
+VkClearValue randomClearValue (const Attachment& attachment, de::Random& rng)
+{
+	const float					clearNan	= tcu::Float32::nan().asFloat();
+	const tcu::TextureFormat	format		= mapVkFormat(attachment.getFormat());
+
+	if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order))
+	{
+		VkClearValue clearValue;
+
+		clearValue.depthStencil.depth	= clearNan;
+		clearValue.depthStencil.stencil	= 255;
+
+		if (tcu::hasStencilComponent(format.order))
+			clearValue.depthStencil.stencil	= rng.getInt(0, 255);
+
+		if (tcu::hasDepthComponent(format.order))
+			clearValue.depthStencil.depth	= rng.getFloat();
+
+		return clearValue;
+	}
+	else
+	{
+		VkClearValue clearValue;
+
+		clearValue.color = randomColorClearValue(attachment, rng);
+
+		return clearValue;
+	}
+}
+
+class AttachmentResources
+{
+public:
+	AttachmentResources (const DeviceInterface&		vk,
+						 VkDevice					device,
+						 Allocator&					allocator,
+						 deUint32					queueIndex,
+						 const UVec2&				size,
+						 const Attachment&			attachmentInfo,
+						 bool						lazy)
+		: m_image			(createAttachmentImage(vk, device, queueIndex, size, attachmentInfo.getFormat(), attachmentInfo.getSamples(), lazy ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0, VK_IMAGE_LAYOUT_UNDEFINED))
+		, m_imageMemory		(createImageMemory(vk, device, allocator, *m_image, lazy))
+		, m_attachmentView	(createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), getImageAspectFlags(attachmentInfo.getFormat())))
+	{
+		if (!lazy)
+		{
+			const tcu::TextureFormat format = mapVkFormat(attachmentInfo.getFormat());
+
+			if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
+			{
+				const tcu::TextureFormat	depthFormat		= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
+				const tcu::TextureFormat	stencilFormat	= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+
+				m_bufferSize			= size.x() * size.y() * depthFormat.getPixelSize();
+				m_secondaryBufferSize	= size.x() * size.y() * stencilFormat.getPixelSize();
+
+				m_buffer				= createBuffer(vk, device, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT, 0, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
+				m_bufferMemory			= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
+
+				bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
+
+				m_secondaryBuffer		= createBuffer(vk, device, m_secondaryBufferSize, VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT, 0, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
+				m_secondaryBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_secondaryBuffer), MemoryRequirement::HostVisible);
+
+				bindBufferMemory(vk, device, *m_secondaryBuffer, m_secondaryBufferMemory->getMemory(), m_secondaryBufferMemory->getOffset());
+			}
+			else
+			{
+				m_bufferSize	= size.x() * size.y() * format.getPixelSize();
+
+				m_buffer		= createBuffer(vk, device, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT, 0, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex);
+				m_bufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), MemoryRequirement::HostVisible);
+
+				bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset());
+			}
+		}
+	}
+
+	~AttachmentResources (void)
+	{
+	}
+
+	VkImageView getAttachmentView (void) const
+	{
+		return *m_attachmentView;
+	}
+
+	VkImage getImage (void) const
+	{
+		return *m_image;
+	}
+
+	VkBuffer getBuffer (void) const
+	{
+		DE_ASSERT(*m_buffer != DE_NULL);
+		return *m_buffer;
+	}
+
+	VkDeviceSize getBufferSize (void) const
+	{
+		DE_ASSERT(*m_buffer != DE_NULL);
+		return m_bufferSize;
+	}
+
+	const Allocation& getResultMemory (void) const
+	{
+		DE_ASSERT(m_bufferMemory);
+		return *m_bufferMemory;
+	}
+
+	VkBuffer getSecondaryBuffer (void) const
+	{
+		DE_ASSERT(*m_secondaryBuffer != DE_NULL);
+		return *m_secondaryBuffer;
+	}
+
+	VkDeviceSize getSecondaryBufferSize (void) const
+	{
+		DE_ASSERT(*m_secondaryBuffer != DE_NULL);
+		return m_secondaryBufferSize;
+	}
+
+	const Allocation& getSecondaryResultMemory (void) const
+	{
+		DE_ASSERT(m_secondaryBufferMemory);
+		return *m_secondaryBufferMemory;
+	}
+
+private:
+	const Unique<VkImage>			m_image;
+	const UniquePtr<Allocation>		m_imageMemory;
+	const Unique<VkImageView>		m_attachmentView;
+
+	Move<VkBuffer>					m_buffer;
+	VkDeviceSize					m_bufferSize;
+	de::MovePtr<Allocation>			m_bufferMemory;
+
+	Move<VkBuffer>					m_secondaryBuffer;
+	VkDeviceSize					m_secondaryBufferSize;
+	de::MovePtr<Allocation>			m_secondaryBufferMemory;
+};
+
+void uploadBufferData (const DeviceInterface&	vk,
+					   VkDevice					device,
+					   const Allocation&		memory,
+					   size_t					size,
+					   const void*				data)
+{
+	const VkMappedMemoryRange range =
+	{
+		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// sType;
+		DE_NULL,								// pNext;
+		memory.getMemory(),						// mem;
+		memory.getOffset(),						// offset;
+		(VkDeviceSize)size						// size;
+	};
+	void* const ptr = memory.getHostPtr();
+
+	deMemcpy(ptr, data, size);
+	VK_CHECK(vk.flushMappedMemoryRanges(device, 1, &range));
+}
+
+VkImageAspect getPrimaryImageAspect (tcu::TextureFormat::ChannelOrder order)
+{
+	DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21);
+
+	switch (order)
+	{
+		case tcu::TextureFormat::D:
+		case tcu::TextureFormat::DS:
+			return VK_IMAGE_ASPECT_DEPTH;
+
+		case tcu::TextureFormat::S:
+			return VK_IMAGE_ASPECT_STENCIL;
+
+		default:
+			return VK_IMAGE_ASPECT_COLOR;
+	}
+}
+
+class RenderQuad
+{
+public:
+	RenderQuad (const Vec4& posA, const Vec4& posB)
+		: m_vertices(6)
+	{
+		m_vertices[0] = posA;
+		m_vertices[1] = Vec4(posA[0], posB[1], posA[2], posA[3]);
+		m_vertices[2] = posB;
+
+		m_vertices[3] = posB;
+		m_vertices[4] = Vec4(posB[0], posA[1], posB[2], posA[3]);
+		m_vertices[5] = posA;
+	}
+
+	const Vec4&		getCornerA			(void) const
+	{
+		return m_vertices[0];
+	}
+
+	const Vec4&		getCornerB			(void) const
+	{
+		return m_vertices[2];
+	}
+
+	const void*		getVertexPointer	(void) const
+	{
+		return &m_vertices[0];
+	}
+
+	size_t			getVertexDataSize	(void) const
+	{
+		return sizeof(Vec4) * m_vertices.size();
+	}
+
+private:
+	vector<Vec4>	m_vertices;
+};
+
+class ColorClear
+{
+public:
+	ColorClear	(const UVec2&				offset,
+				 const UVec2&				size,
+				 const VkClearColorValue&	color)
+		: m_offset	(offset)
+		, m_size	(size)
+		, m_color	(color)
+	{
+	}
+
+	const UVec2&				getOffset		(void) const { return m_offset;		}
+	const UVec2&				getSize			(void) const { return m_size;		}
+	const VkClearColorValue&	getColor		(void) const { return m_color;		}
+
+private:
+	UVec2				m_offset;
+	UVec2				m_size;
+	VkClearColorValue	m_color;
+};
+
+class DepthStencilClear
+{
+public:
+	DepthStencilClear	(const UVec2&				offset,
+						 const UVec2&				size,
+						 float						depth,
+						 deUint32					stencil)
+		: m_offset	(offset)
+		, m_size	(size)
+		, m_depth	(depth)
+		, m_stencil	(stencil)
+	{
+	}
+
+	const UVec2&		getOffset		(void) const { return m_offset;		}
+	const UVec2&		getSize			(void) const { return m_size;		}
+	float				getDepth		(void) const { return m_depth;		}
+	deUint32			getStencil		(void) const { return m_stencil;	}
+
+private:
+	UVec2				m_offset;
+	UVec2				m_size;
+
+	float				m_depth;
+	deUint32			m_stencil;
+};
+
+class SubpassRenderInfo
+{
+public:
+	SubpassRenderInfo	(const RenderPass&					renderPass,
+						 deUint32							subpassIndex,
+
+						 bool								isSecondary_,
+
+						 const UVec2&						viewportOffset,
+						 const UVec2&						viewportSize,
+
+						 const Maybe<RenderQuad>&			renderQuad,
+						 const vector<ColorClear>&			colorClears,
+						 const Maybe<DepthStencilClear>&	depthStencilClear)
+		: m_viewportOffset		(viewportOffset)
+		, m_viewportSize		(viewportSize)
+		, m_subpassIndex		(subpassIndex)
+		, m_isSecondary			(isSecondary_)
+		, m_flags				(renderPass.getSubpasses()[subpassIndex].getFlags())
+		, m_renderQuad			(renderQuad)
+		, m_colorClears			(colorClears)
+		, m_depthStencilClear	(depthStencilClear)
+		, m_colorAttachments	(renderPass.getSubpasses()[subpassIndex].getColorAttachments())
+	{
+		for (deUint32 attachmentNdx = 0; attachmentNdx < (deUint32)m_colorAttachments.size(); attachmentNdx++)
+			m_colorAttachmentInfo.push_back(renderPass.getAttachments()[m_colorAttachments[attachmentNdx].getAttachment()]);
+
+		if (renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
+		{
+			m_depthStencilAttachment		= tcu::just(renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment());
+			m_depthStencilAttachmentInfo	= tcu::just(renderPass.getAttachments()[renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment()]);
+		}
+	}
+
+	const UVec2&						getViewportOffset				(void) const { return m_viewportOffset;		}
+	const UVec2&						getViewportSize					(void) const { return m_viewportSize;		}
+
+	deUint32							getSubpassIndex					(void) const { return m_subpassIndex;		}
+	bool								isSecondary						(void) const { return m_isSecondary;		}
+
+	const Maybe<RenderQuad>&			getRenderQuad					(void) const { return m_renderQuad;			}
+	const vector<ColorClear>&			getColorClears					(void) const { return m_colorClears;		}
+	const Maybe<DepthStencilClear>&		getDepthStencilClear			(void) const { return m_depthStencilClear;	}
+
+	deUint32							getColorAttachmentCount			(void) const { return (deUint32)m_colorAttachments.size(); }
+	VkImageLayout						getColorAttachmentLayout		(deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getImageLayout(); }
+	deUint32							getColorAttachmentIndex			(deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getAttachment(); }
+	const Attachment&					getColorAttachment				(deUint32 attachmentNdx) const { return m_colorAttachmentInfo[attachmentNdx]; }
+	Maybe<VkImageLayout>				getDepthStencilAttachmentLayout	(void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getImageLayout()) : tcu::nothing<VkImageLayout>(); }
+	Maybe<deUint32>						getDepthStencilAttachmentIndex	(void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getAttachment()) : tcu::nothing<deUint32>(); };
+	const Maybe<Attachment>&			getDepthStencilAttachment		(void) const { return m_depthStencilAttachmentInfo; }
+	VkSubpassDescriptionFlags			getSubpassFlags					(void) const { return m_flags; }
+private:
+	UVec2								m_viewportOffset;
+	UVec2								m_viewportSize;
+
+	deUint32							m_subpassIndex;
+	bool								m_isSecondary;
+	VkSubpassDescriptionFlags			m_flags;
+
+	Maybe<RenderQuad>					m_renderQuad;
+	vector<ColorClear>					m_colorClears;
+	Maybe<DepthStencilClear>			m_depthStencilClear;
+
+	vector<AttachmentReference>			m_colorAttachments;
+	vector<Attachment>					m_colorAttachmentInfo;
+
+	Maybe<AttachmentReference>			m_depthStencilAttachment;
+	Maybe<Attachment>					m_depthStencilAttachmentInfo;
+};
+
+Move<VkPipeline> createSubpassPipeline (const DeviceInterface&		vk,
+										VkDevice					device,
+										VkRenderPass				renderPass,
+										VkShader					vertexShader,
+										VkShader					fragmentShader,
+										VkPipelineLayout			pipelineLayout,
+										const SubpassRenderInfo&	renderInfo)
+{
+	const VkSpecializationInfo emptyShaderSpecializations =
+	{
+		0u,			// mapEntryCount
+		DE_NULL,	// pMap
+		0u,			// dataSize
+		DE_NULL,	// pData
+	};
+
+	Maybe<deUint32>								rasterSamples;
+	vector<VkPipelineColorBlendAttachmentState>	attachmentBlendStates;
+
+	for (deUint32 attachmentNdx = 0; attachmentNdx < renderInfo.getColorAttachmentCount(); attachmentNdx++)
+	{
+		const Attachment&			attachment		= renderInfo.getColorAttachment(attachmentNdx);
+
+		DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
+
+		rasterSamples = attachment.getSamples();
+
+		{
+			const VkPipelineColorBlendAttachmentState	attachmentBlendState =
+			{
+				VK_FALSE,																// blendEnable
+				VK_BLEND_SRC_ALPHA,														// srcBlendColor
+				VK_BLEND_ONE_MINUS_SRC_ALPHA,											// destBlendColor
+				VK_BLEND_OP_ADD,														// blendOpColor
+				VK_BLEND_ONE,															// srcBlendAlpha
+				VK_BLEND_ONE,															// destBlendAlpha
+				VK_BLEND_OP_ADD,														// blendOpAlpha
+				VK_CHANNEL_R_BIT|VK_CHANNEL_G_BIT|VK_CHANNEL_B_BIT|VK_CHANNEL_A_BIT,	// channelWriteMask
+			};
+
+			attachmentBlendStates.push_back(attachmentBlendState);
+		}
+	}
+
+	if (renderInfo.getDepthStencilAttachment())
+	{
+		const Attachment& attachment = *renderInfo.getDepthStencilAttachment();
+
+		DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples());
+		rasterSamples = attachment.getSamples();
+	}
+
+	// If there are no attachment use single sample
+	if (!rasterSamples)
+		rasterSamples = 1;
+
+	const VkPipelineShaderStageCreateInfo shaderStages[2] =
+	{
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
+			DE_NULL,												// pNext
+
+			VK_SHADER_STAGE_VERTEX,									// stage
+			vertexShader,											// shader
+			&emptyShaderSpecializations
+		},
+		{
+			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
+			DE_NULL,												// pNext
+
+			VK_SHADER_STAGE_FRAGMENT,								// stage
+			fragmentShader,											// shader
+			&emptyShaderSpecializations
+		}
+	};
+	const VkVertexInputBindingDescription vertexBinding =
+	{
+		0u,															// binding
+		(deUint32)sizeof(tcu::Vec4),								// strideInBytes
+		VK_VERTEX_INPUT_STEP_RATE_VERTEX,							// stepRate
+	};
+	const VkVertexInputAttributeDescription vertexAttrib =
+	{
+		0u,															// location
+		0u,															// binding
+		VK_FORMAT_R32G32B32A32_SFLOAT,								// format
+		0u,															// offsetInBytes
+	};
+	const VkPipelineVertexInputStateCreateInfo vertexInputState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	sType
+		DE_NULL,													//	pNext
+		1u,															//	bindingCount
+		&vertexBinding,												//	pVertexBindingDescriptions
+		1u,															//	attributeCount
+		&vertexAttrib,												//	pVertexAttributeDescriptions
+	};
+	const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// sType
+		DE_NULL,														// pNext
+		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// topology
+		VK_FALSE,														// primitiveRestartEnable
+	};
+	const VkViewport viewport =
+	{
+		(float)renderInfo.getViewportOffset().x(),	(float)renderInfo.getViewportOffset().y(),
+		(float)renderInfo.getViewportSize().x(),	(float)renderInfo.getViewportSize().y(),
+		0.0f, 1.0f
+	};
+	const VkRect2D scissor =
+	{
+		{ (deInt32)renderInfo.getViewportOffset().x(),	(deInt32)renderInfo.getViewportOffset().y() },
+		{ (deInt32)renderInfo.getViewportSize().x(),	(deInt32)renderInfo.getViewportSize().y() }
+	};
+	const VkPipelineViewportStateCreateInfo viewportState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+		DE_NULL,
+		1u,
+		&viewport,
+		1u,
+		&scissor
+	};
+	const VkPipelineRasterStateCreateInfo rasterState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,			// sType
+		DE_NULL,														// pNext
+		VK_TRUE,														// depthClipEnable
+		VK_FALSE,														// rasterizerDiscardEnable
+		VK_FILL_MODE_SOLID,												// fillMode
+		VK_CULL_MODE_NONE,												// cullMode
+		VK_FRONT_FACE_CCW,												// frontFace
+		VK_FALSE,														// depthBiasEnable
+		0.0f,															// depthBias
+		0.0f,															// depthBiasClamp
+		0.0f,															// slopeScaledDepthBias
+		1.0f															// lineWidth
+	};
+	const VkPipelineMultisampleStateCreateInfo multisampleState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// sType
+		DE_NULL,														// pNext
+		*rasterSamples,													// rasterSamples
+		VK_FALSE,														// sampleShadingEnable
+		0.0f,															// minSampleShading
+		DE_NULL															// pSampleMask
+	};
+	const VkPipelineDepthStencilStateCreateInfo depthStencilState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// sType
+		DE_NULL,													// pNext
+		VK_TRUE,													// depthTestEnable
+		VK_TRUE,													// depthWriteEnable
+		VK_COMPARE_OP_ALWAYS,										// depthCompareOp
+		VK_FALSE,													// depthBoundsEnable
+		VK_TRUE,													// stencilTestEnable
+		{
+			VK_STENCIL_OP_REPLACE,									// stencilFailOp
+			VK_STENCIL_OP_REPLACE,									// stencilPassOp
+			VK_STENCIL_OP_REPLACE,									// stencilDepthFailOp
+			VK_COMPARE_OP_ALWAYS,									// stencilCompareOp
+			~0u,													// stencilCompareMask
+			~0u,													// stencilWriteMask
+			~0u														// stencilReference
+		},															// front
+		{
+			VK_STENCIL_OP_REPLACE,									// stencilFailOp
+			VK_STENCIL_OP_REPLACE,									// stencilPassOp
+			VK_STENCIL_OP_REPLACE,									// stencilDepthFailOp
+			VK_COMPARE_OP_ALWAYS,									// stencilCompareOp
+			~0u,													// stencilCompareMask
+			~0u,													// stencilWriteMask
+			~0u														// stencilReference
+		},															// back
+
+		-1.0f,														// minDepthBounds;
+		1.0f														// maxDepthBounds;
+	};
+	const VkPipelineColorBlendStateCreateInfo blendState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,			// sType
+		DE_NULL,															// pNext
+		VK_FALSE,															// alphaToCoverageEnable
+		VK_FALSE,															// alphaToOneEnable
+		VK_FALSE,															// logicOpEnable
+		VK_LOGIC_OP_COPY,													// logicOp
+		(deUint32)attachmentBlendStates.size(),								// attachmentCount
+		attachmentBlendStates.empty() ? DE_NULL : &attachmentBlendStates[0],// pAttachments
+		{ 0.0f, 0.0f, 0.0f, 0.0f }											// blendConst
+	};
+	const VkPipelineDynamicStateCreateInfo dynamicState =
+	{
+		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+		DE_NULL,
+		0,
+		DE_NULL
+	};
+	const VkGraphicsPipelineCreateInfo createInfo =
+	{
+		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,		// sType
+		DE_NULL,												// pNext
+
+		2,														// stageCount
+		shaderStages,											// pStages
+
+		&vertexInputState,										// pVertexInputState
+		&inputAssemblyState,									// pInputAssemblyState
+		DE_NULL,												// pTessellationState
+		&viewportState,											// pViewportState
+		&rasterState,											// pRasterState
+		&multisampleState,										// pMultisampleState
+		&depthStencilState,										// pDepthStencilState
+		&blendState,											// pColorBlendState
+		&dynamicState,											// pDynamicState
+		0u,														// flags
+		pipelineLayout,											// layout
+
+		renderPass,												// renderPass
+		renderInfo.getSubpassIndex(),							// subpass
+		DE_NULL,												// basePipelineHandle
+		0u														// basePipelineIndex
+	};
+
+	return createGraphicsPipeline(vk, device, DE_NULL, &createInfo);
+}
+
+class SubpassRenderer
+{
+public:
+	SubpassRenderer (Context&					context,
+					 const DeviceInterface&		vk,
+					 VkDevice					device,
+					 Allocator&					allocator,
+					 VkRenderPass				renderPass,
+					 VkFramebuffer				framebuffer,
+					 VkCmdPool					commandBufferPool,
+					 deUint32					queueFamilyIndex,
+					 const SubpassRenderInfo&	renderInfo)
+		: m_renderInfo	(renderInfo)
+	{
+		const deUint32 subpassIndex = renderInfo.getSubpassIndex();
+
+		if (renderInfo.getRenderQuad())
+		{
+			const RenderQuad&					renderQuad				= *renderInfo.getRenderQuad();
+			const VkPipelineLayoutCreateInfo	pipelineLayoutParams	=
+			{
+				VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// sType;
+				DE_NULL,										// pNext;
+				0u,												// descriptorSetCount;
+				DE_NULL,										// pSetLayouts;
+				0u,												// pushConstantRangeCount;
+				DE_NULL,										// pPushConstantRanges;
+			};
+
+			m_vertexShaderModule	= createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-vert"), 0u);
+			m_fragmentShaderModule	= createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-frag"), 0u);
+			m_vertexShader			= createShader(vk, device, *m_vertexShaderModule, "main", 0u, VK_SHADER_STAGE_VERTEX);
+			m_fragmentShader		= createShader(vk, device, *m_fragmentShaderModule, "main", 0u, VK_SHADER_STAGE_FRAGMENT);
+			m_pipelineLayout		= createPipelineLayout(vk, device, &pipelineLayoutParams);
+			m_pipeline				= createSubpassPipeline(vk, device, renderPass, *m_vertexShader, *m_fragmentShader, *m_pipelineLayout, m_renderInfo);
+
+			m_vertexBuffer			= createBuffer(vk, device, (VkDeviceSize)renderQuad.getVertexDataSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 0u, VK_SHARING_MODE_EXCLUSIVE, 1u, &queueFamilyIndex);
+			m_vertexBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vk, device, *m_vertexBuffer), MemoryRequirement::HostVisible);
+
+			bindBufferMemory(vk, device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset());
+			uploadBufferData(vk, device, *m_vertexBufferMemory, renderQuad.getVertexDataSize(), renderQuad.getVertexPointer());
+		}
+
+		if (renderInfo.isSecondary())
+		{
+			m_commandBuffer = createCommandBuffer(vk, device, commandBufferPool, VK_CMD_BUFFER_LEVEL_SECONDARY, 0u);
+
+			beginCommandBuffer(vk, *m_commandBuffer, 0u, renderPass, subpassIndex, framebuffer);
+			pushRenderCommands(vk, *m_commandBuffer);
+			endCommandBuffer(vk, *m_commandBuffer);
+		}
+	}
+
+	bool isSecondary (void) const
+	{
+		return m_commandBuffer;
+	}
+
+	VkCmdBuffer getCommandBuffer (void) const
+	{
+		DE_ASSERT(isSecondary());
+		return *m_commandBuffer;
+	}
+
+	void pushRenderCommands (const DeviceInterface&		vk,
+							 VkCmdBuffer				commandBuffer)
+	{
+		if (!m_renderInfo.getColorClears().empty())
+		{
+			const vector<ColorClear>&	colorClears	(m_renderInfo.getColorClears());
+
+			for (deUint32 attachmentNdx = 0; attachmentNdx < m_renderInfo.getColorAttachmentCount(); attachmentNdx++)
+			{
+				const ColorClear&		colorClear	= colorClears[attachmentNdx];
+				const VkClearColorValue	color		= colorClear.getColor();
+				const VkRect3D			rect		=
+				{
+					{ (deInt32)colorClear.getOffset().x(),	(deInt32)colorClear.getOffset().y(),	0 },
+					{ (deInt32)colorClear.getSize().x(),	(deInt32)colorClear.getSize().y(),		1 }
+				};
+
+				vk.cmdClearColorAttachment(commandBuffer, attachmentNdx, m_renderInfo.getColorAttachmentLayout(attachmentNdx), &color, 1, &rect);
+			}
+		}
+
+		if (m_renderInfo.getDepthStencilClear())
+		{
+			const DepthStencilClear&		depthStencilClear	= *m_renderInfo.getDepthStencilClear();
+			const float						depth				= depthStencilClear.getDepth();
+			const deUint32					stencil				= depthStencilClear.getStencil();
+			const VkClearDepthStencilValue	depthStencil	=
+			{
+				depth,
+				stencil
+			};
+			const VkRect3D					rect				=
+			{
+				{ (deInt32)depthStencilClear.getOffset().x(),	(deInt32)depthStencilClear.getOffset().y(),	0 },
+				{ (deInt32)depthStencilClear.getSize().x(),		(deInt32)depthStencilClear.getSize().y(),	1 }
+			};
+
+			vk.cmdClearDepthStencilAttachment(commandBuffer, getImageAspectFlags(m_renderInfo.getDepthStencilAttachment()->getFormat()), *m_renderInfo.getDepthStencilAttachmentLayout(), &depthStencil, 1, &rect);
+		}
+
+		// \note Assumes that clears are considered to be primitives, but
+		// clears to different attachments are not considered to overlap.
+		if ((m_renderInfo.getDepthStencilClear() || !m_renderInfo.getColorClears().empty())
+			&& m_renderInfo.getRenderQuad()
+			&& m_renderInfo.getSubpassFlags() & VK_SUBPASS_DESCRIPTION_NO_OVERDRAW_BIT)
+		{
+			vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_TRUE, 0, DE_NULL);
+		}
+
+		if (m_renderInfo.getRenderQuad())
+		{
+			const VkDeviceSize	offset			= 0;
+			const VkBuffer		vertexBuffer	= *m_vertexBuffer;
+
+			vk.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
+			vk.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &vertexBuffer, &offset);
+			vk.cmdDraw(commandBuffer, 6u, 1u, 0u, 0u);
+		}
+	}
+
+private:
+	const SubpassRenderInfo				m_renderInfo;
+	Move<VkCmdBuffer>					m_commandBuffer;
+	Move<VkPipeline>					m_pipeline;
+	Move<VkPipelineLayout>				m_pipelineLayout;
+
+	Move<VkShaderModule>				m_vertexShaderModule;
+	Move<VkShader>						m_vertexShader;
+
+	Move<VkShaderModule>				m_fragmentShaderModule;
+	Move<VkShader>						m_fragmentShader;
+
+	Move<VkBuffer>						m_vertexBuffer;
+	de::MovePtr<Allocation>				m_vertexBufferMemory;
+};
+
+void pushImageInitializationCommands (const DeviceInterface&								vk,
+									  VkCmdBuffer											commandBuffer,
+									  const vector<Attachment>&								attachmentInfo,
+									  const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
+									  deUint32												queueIndex,
+									  const vector<Maybe<VkClearValue> >&					clearValues)
+{
+	{
+		vector<VkImageMemoryBarrier>	initializeLayouts;
+
+		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+		{
+			if (!clearValues[attachmentNdx])
+				continue;
+
+			const VkImageMemoryBarrier barrier =
+			{
+				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,								// sType;
+				DE_NULL,															// pNext;
+
+				getAllMemoryOutputFlags(),											// outputMask
+				getAllMemoryInputFlags(),											// inputMask
+
+				VK_IMAGE_LAYOUT_UNDEFINED,											// oldLayout
+				VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,						// newLayout;
+
+				queueIndex,															// srcQueueFamilyIndex;
+				queueIndex,															// destQueueFamilyIndex;
+
+				attachmentResources[attachmentNdx]->getImage(),						// image;
+				{																	// subresourceRange;
+					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),	// aspect;
+					0,																// baseMipLevel;
+					1,																// mipLevels;
+					0,																// baseArraySlice;
+					1																// arraySize;
+				}
+			};
+
+			initializeLayouts.push_back(barrier);
+		}
+
+		if (!initializeLayouts.empty())
+		{
+			vector<VkImageMemoryBarrier*> initializeLayoutPtrs;
+
+			for (size_t ndx = 0; ndx < initializeLayouts.size(); ndx++)
+				initializeLayoutPtrs.push_back(&initializeLayouts[ndx]);
+
+			vk.cmdPipelineBarrier(commandBuffer, 0, 0, VK_FALSE, (deUint32)initializeLayouts.size(), (const void* const*)&initializeLayoutPtrs[0]);
+		}
+	}
+
+	for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+	{
+		if (!clearValues[attachmentNdx])
+			continue;
+
+		const tcu::TextureFormat format = mapVkFormat(attachmentInfo[attachmentNdx].getFormat());
+
+		if (hasStencilComponent(format.order) || hasDepthComponent(format.order))
+		{
+			const float						clearNan		= tcu::Float32::nan().asFloat();
+			const float						clearDepth		= hasDepthComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.depth : clearNan;
+			const deUint32					clearStencil	= hasStencilComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.stencil : ~0u;
+			const VkClearDepthStencilValue	depthStencil	=
+			{
+				clearDepth,
+				clearStencil
+			};
+			const VkImageSubresourceRange range =
+			{
+				hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH : 0
+					| hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL : 0,
+				0,
+				1,
+				0,
+				1
+			};
+
+			vk.cmdClearDepthStencilImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, &depthStencil, 1, &range);
+		}
+		else
+		{
+			const VkImageSubresourceRange	range		=
+			{
+				VK_IMAGE_ASPECT_COLOR,					// aspect;
+				0,										// baseMipLevel;
+				1,										// mipLevels;
+				0,										// baseArraySlice;
+				1										// arraySize;
+			};
+			const VkClearColorValue			clearColor	= clearValues[attachmentNdx]->color;
+
+			vk.cmdClearColorImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, &clearColor, 1, &range);
+		}
+	}
+
+	{
+		vector<VkImageMemoryBarrier>	renderPassLayouts;
+
+		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+		{
+			const VkImageMemoryBarrier barrier =
+			{
+				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,								// sType;
+				DE_NULL,															// pNext;
+
+				getAllMemoryOutputFlags(),											// outputMask
+				getAllMemoryInputFlags(),											// inputMask
+
+				clearValues[attachmentNdx] ?
+					VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL
+					: VK_IMAGE_LAYOUT_UNDEFINED,									// oldLayout
+
+				attachmentInfo[attachmentNdx].getInitialLayout(),					// newLayout;
+
+				queueIndex,															// srcQueueFamilyIndex;
+				queueIndex,															// destQueueFamilyIndex;
+
+				attachmentResources[attachmentNdx]->getImage(),						// image;
+				{																	// subresourceRange;
+					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),	// aspect;
+					0,																// baseMipLevel;
+					1,																// mipLevels;
+					0,																// baseArraySlice;
+					1																// arraySize;
+				}
+			};
+
+			renderPassLayouts.push_back(barrier);
+		}
+
+		if (!renderPassLayouts.empty())
+		{
+			vector<VkImageMemoryBarrier*> renderPassLayoutPtrs;
+
+			for (size_t ndx = 0; ndx < renderPassLayouts.size(); ndx++)
+				renderPassLayoutPtrs.push_back(&renderPassLayouts[ndx]);
+
+			vk.cmdPipelineBarrier(commandBuffer, 0, 0, VK_FALSE, (deUint32)renderPassLayouts.size(), (const void* const*)&renderPassLayoutPtrs[0]);
+		}
+	}
+}
+
+void pushRenderPassCommands (const DeviceInterface&								vk,
+							 VkCmdBuffer										commandBuffer,
+							 VkRenderPass										renderPass,
+							 VkFramebuffer										framebuffer,
+							 const vector<de::SharedPtr<SubpassRenderer> >&		subpassRenderers,
+							 const UVec2&										renderPos,
+							 const UVec2&										renderSize,
+							 const vector<Maybe<VkClearValue> >&				renderPassClearValues,
+							 TestConfig::RenderTypes							render)
+{
+	const float				clearNan				= tcu::Float32::nan().asFloat();
+	vector<VkClearValue>	attachmentClearValues;
+
+	for (size_t attachmentNdx = 0; attachmentNdx < renderPassClearValues.size(); attachmentNdx++)
+	{
+		if (renderPassClearValues[attachmentNdx])
+			attachmentClearValues.push_back(*renderPassClearValues[attachmentNdx]);
+		else
+			attachmentClearValues.push_back(makeClearValueColorF32(clearNan, clearNan, clearNan, clearNan));
+	}
+
+	{
+		const VkRect2D renderArea =
+		{
+			{ (deInt32)renderPos.x(),	(deInt32)renderPos.y() },
+			{ (deInt32)renderSize.x(),	(deInt32)renderSize.y() }
+		};
+
+		for (size_t subpassNdx = 0; subpassNdx < subpassRenderers.size(); subpassNdx++)
+		{
+			const VkRenderPassContents	contents = subpassRenderers[subpassNdx]->isSecondary() ? VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS : VK_RENDER_PASS_CONTENTS_INLINE;
+
+			if (subpassNdx == 0)
+				cmdBeginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, (deUint32)attachmentClearValues.size(), attachmentClearValues.empty() ? DE_NULL : &attachmentClearValues[0], contents);
+			else
+				vk.cmdNextSubpass(commandBuffer, contents);
+
+			if (render)
+			{
+				if (contents == VK_RENDER_PASS_CONTENTS_INLINE)
+				{
+					subpassRenderers[subpassNdx]->pushRenderCommands(vk, commandBuffer);
+				}
+				else if (contents == VK_RENDER_PASS_CONTENTS_SECONDARY_CMD_BUFFERS)
+				{
+					const VkCmdBuffer cmd = subpassRenderers[subpassNdx]->getCommandBuffer();
+					vk.cmdExecuteCommands(commandBuffer, 1, &cmd);
+				}
+				else
+					DE_FATAL("Invalid contents");
+			}
+		}
+
+		vk.cmdEndRenderPass(commandBuffer);
+	}
+}
+
+void pushReadImagesToBuffers (const DeviceInterface&								vk,
+							  VkCmdBuffer											commandBuffer,
+							  deUint32												queueIndex,
+
+							  const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
+							  const vector<Attachment>&								attachmentInfo,
+							  const vector<bool>&									isLazy,
+
+							  const UVec2&											targetSize)
+{
+	{
+		vector<VkImageMemoryBarrier>	imageBarriers;
+
+		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+		{
+			if (isLazy[attachmentNdx])
+				continue;
+
+			const VkImageMemoryBarrier barrier =
+			{
+				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// sType
+				DE_NULL,											// pNext
+
+				getAllMemoryOutputFlags(),							// outputMask
+				getAllMemoryInputFlags(),							// inputMask
+
+				attachmentInfo[attachmentNdx].getFinalLayout(),		// oldLayout
+				VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,			// newLayout
+
+				queueIndex,											// srcQueueFamilyIndex
+				queueIndex,											// destQueueFamilyIndex
+
+				attachmentResources[attachmentNdx]->getImage(),		// image
+				{													// subresourceRange
+					getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()),	// aspect;
+					0,										// baseMipLevel
+					1,										// mipLevels
+					0,										// baseArraySlice
+					1										// arraySize
+				}
+			};
+
+			imageBarriers.push_back(barrier);
+		}
+
+		if (!imageBarriers.empty())
+		{
+			vector<VkImageMemoryBarrier*> clearLayoutPtrs;
+
+			for (size_t ndx = 0; ndx < imageBarriers.size(); ndx++)
+				clearLayoutPtrs.push_back(&imageBarriers[ndx]);
+
+			vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(),
+												 getAllPipelineStageFlags(),
+												 VK_FALSE, (deUint32)imageBarriers.size(), (const void* const*)&clearLayoutPtrs[0]);
+		}
+	}
+
+	for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+	{
+		if (isLazy[attachmentNdx])
+			continue;
+
+		const tcu::TextureFormat::ChannelOrder	order	= mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
+		const VkBufferImageCopy					rect	=
+		{
+			0, // bufferOffset
+			0, // bufferRowLength
+			0, // bufferImageHeight
+			{							// imageSubresource
+				getPrimaryImageAspect(mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order),	// aspect
+				0, 						// mipLevel
+				0,						// arraySlice
+				1						// arraySize
+			},
+			{ 0, 0, 0 }, 				// imageOffset
+			{ (deInt32)targetSize.x(), (deInt32)targetSize.y(), 1 }		// imageExtent
+		};
+
+		vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, attachmentResources[attachmentNdx]->getBuffer(), 1, &rect);
+
+		if (tcu::TextureFormat::DS == order)
+		{
+			const VkBufferImageCopy stencilRect =
+			{
+				0, // bufferOffset
+				0, // bufferRowLength
+				0, // bufferImageHeight
+				{								// imageSubresource
+					VK_IMAGE_ASPECT_STENCIL,	// aspect
+					0,							// mipLevel
+					0,							// arraySlice
+					1						// arraySize
+				},
+				{ 0, 0, 0 }, 				// imageOffset
+				{ (deInt32)targetSize.x(), (deInt32)targetSize.y(), 1 }		// imageExtent
+			};
+
+			vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, attachmentResources[attachmentNdx]->getSecondaryBuffer(), 1, &stencilRect);
+		}
+	}
+
+	{
+		vector<VkBufferMemoryBarrier>	bufferBarriers;
+
+		for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++)
+		{
+			if (isLazy[attachmentNdx])
+				continue;
+
+			const tcu::TextureFormat::ChannelOrder	order			= mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order;
+			const VkBufferMemoryBarrier				bufferBarrier	=
+			{
+				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+				DE_NULL,
+
+				getAllMemoryOutputFlags(),
+				getAllMemoryInputFlags(),
+
+				queueIndex,
+				queueIndex,
+
+				attachmentResources[attachmentNdx]->getBuffer(),
+				0,
+				attachmentResources[attachmentNdx]->getBufferSize()
+			};
+
+			bufferBarriers.push_back(bufferBarrier);
+
+			if (tcu::TextureFormat::DS == order)
+			{
+				const VkBufferMemoryBarrier secondaryBufferBarrier =
+				{
+					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+					DE_NULL,
+
+					getAllMemoryOutputFlags(),
+					getAllMemoryInputFlags(),
+
+					queueIndex,
+					queueIndex,
+
+					attachmentResources[attachmentNdx]->getSecondaryBuffer(),
+					0,
+					attachmentResources[attachmentNdx]->getSecondaryBufferSize()
+				};
+
+				bufferBarriers.push_back(secondaryBufferBarrier);
+			}
+
+			bufferBarriers.push_back(bufferBarrier);
+		}
+
+		if (!bufferBarriers.empty())
+		{
+			vector<VkBufferMemoryBarrier*> clearLayoutPtrs;
+
+			for (size_t ndx = 0; ndx < bufferBarriers.size(); ndx++)
+				clearLayoutPtrs.push_back(&bufferBarriers[ndx]);
+
+			vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(),
+												 getAllPipelineStageFlags(),
+												 VK_FALSE, (deUint32)bufferBarriers.size(), (const void* const*)&clearLayoutPtrs[0]);
+		}
+	}
+}
+
+void clear (const PixelBufferAccess& access, const VkClearValue& value)
+{
+	const tcu::TextureFormat&	format	= access.getFormat();
+
+	if (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
+	{
+		if (tcu::hasDepthComponent(format.order))
+			tcu::clearDepth(access, value.depthStencil.depth);
+
+		if (tcu::hasStencilComponent(format.order))
+			tcu::clearStencil(access, value.depthStencil.stencil);
+	}
+	else
+	{
+		if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT
+				|| tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT
+				|| tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
+		{
+			const tcu::Vec4		color	(value.color.float32[0],
+										 value.color.float32[1],
+										 value.color.float32[2],
+										 value.color.float32[3]);
+
+			if (tcu::isSRGB(format))
+				tcu::clear(access, tcu::linearToSRGB(color));
+			else
+				tcu::clear(access, color);
+		}
+		else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
+		{
+			const tcu::UVec4	color	(value.color.uint32[0],
+										 value.color.uint32[1],
+										 value.color.uint32[2],
+										 value.color.uint32[3]);
+
+			tcu::clear(access, color);
+		}
+		else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
+		{
+			const tcu::IVec4	color	(value.color.int32[0],
+										 value.color.int32[1],
+										 value.color.int32[2],
+										 value.color.int32[3]);
+
+			tcu::clear(access, color);
+		}
+		else
+			DE_FATAL("Unknown channel class");
+	}
+}
+
+Vec4 computeUvs (const IVec2& posA, const IVec2& posB, const IVec2& pos)
+{
+	const float u = de::clamp((float)(pos.x() - posA.x()) / (float)(posB.x() - posA.x()), 0.0f, 1.0f);
+	const float v = de::clamp((float)(pos.y() - posA.y()) / (float)(posB.y() - posA.y()), 0.0f, 1.0f);
+
+	return Vec4(u, v, u * v, (u + v) / 2.0f);
+}
+
+void renderReferenceImages (vector<tcu::TextureLevel>&			referenceAttachments,
+							const RenderPass&					renderPassInfo,
+							const UVec2&						targetSize,
+							const vector<Maybe<VkClearValue> >&	imageClearValues,
+							const vector<Maybe<VkClearValue> >&	renderPassClearValues,
+							const vector<SubpassRenderInfo>&	subpassRenderInfo,
+							const UVec2&						renderPos,
+							const UVec2&						renderSize)
+{
+	const vector<Subpass>&	subpasses		= renderPassInfo.getSubpasses();
+	vector<bool>			attachmentUsed	(renderPassInfo.getAttachments().size(), false);
+
+	referenceAttachments.resize(renderPassInfo.getAttachments().size());
+
+	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
+	{
+		const Attachment				attachment					= renderPassInfo.getAttachments()[attachmentNdx];
+		const tcu::TextureFormat		format						= mapVkFormat(attachment.getFormat());
+		const tcu::TextureFormatInfo	textureInfo					= tcu::getTextureFormatInfo(format);
+		tcu::TextureLevel&				reference					= referenceAttachments[attachmentNdx];
+		const bool						isDepthOrStencilAttachment	= hasDepthComponent(format.order) || hasStencilComponent(format.order);
+
+		reference = tcu::TextureLevel(format, targetSize.x(), targetSize.y());
+
+		if (imageClearValues[attachmentNdx])
+			clear(reference.getAccess(), *imageClearValues[attachmentNdx]);
+		else
+		{
+			// Fill with grid if image contentst are undefined before renderpass
+			if (isDepthOrStencilAttachment)
+			{
+				if (tcu::hasDepthComponent(format.order))
+					tcu::fillWithGrid(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), 2, textureInfo.valueMin, textureInfo.valueMax);
+
+				if (tcu::hasStencilComponent(format.order))
+					tcu::fillWithGrid(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), 2, textureInfo.valueMin, textureInfo.valueMax);
+			}
+			else
+				tcu::fillWithGrid(reference.getAccess(), 2, textureInfo.valueMin, textureInfo.valueMax);
+		}
+	}
+
+	for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
+	{
+		const Subpass&						subpass				= subpasses[subpassNdx];
+		const SubpassRenderInfo&			renderInfo			= subpassRenderInfo[subpassNdx];
+		const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
+
+		// Apply load op if attachment was used for the first time
+		for (size_t attachmentNdx = 0; attachmentNdx < colorAttachments.size(); attachmentNdx++)
+		{
+			const deUint32 attachmentIndex = colorAttachments[attachmentNdx].getAttachment();
+
+			if (!attachmentUsed[attachmentIndex])
+			{
+				const Attachment&	attachment	= renderPassInfo.getAttachments()[attachmentIndex];
+				tcu::TextureLevel&	reference	= referenceAttachments[attachmentIndex];
+
+				DE_ASSERT(!tcu::hasDepthComponent(reference.getFormat().order));
+				DE_ASSERT(!tcu::hasStencilComponent(reference.getFormat().order));
+
+				if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+					clear(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
+				else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+				{
+					const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
+
+					tcu::fillWithGrid(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
+				}
+
+				attachmentUsed[attachmentIndex] = true;
+			}
+		}
+
+		// Apply load op to depth/stencil attachment if it was used for the first time 
+		if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && !attachmentUsed[subpass.getDepthStencilAttachment().getAttachment()])
+		{
+			const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment();
+
+			// Apply load op if attachment was used for the first time
+			if (!attachmentUsed[attachmentIndex])
+			{
+				const Attachment&	attachment	= renderPassInfo.getAttachments()[attachmentIndex];
+				tcu::TextureLevel&	reference		= referenceAttachments[attachmentIndex];
+
+				if (tcu::hasDepthComponent(reference.getFormat().order))
+				{
+					if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+						clear(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
+					else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+					{
+						const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
+
+						tcu::fillWithGrid(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
+					}
+				}
+
+				if (tcu::hasStencilComponent(reference.getFormat().order))
+				{
+					if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+						clear(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), *renderPassClearValues[attachmentIndex]);
+					else if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+					{
+						const tcu::TextureFormatInfo textureInfo = tcu::getTextureFormatInfo(reference.getFormat());
+
+						tcu::fillWithGrid(tcu::getSubregion(tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
+					}
+				}
+			}
+
+			attachmentUsed[attachmentIndex] = true;
+		}
+
+		for (size_t colorClearNdx = 0; colorClearNdx < renderInfo.getColorClears().size(); colorClearNdx++)
+		{
+			const ColorClear&	colorClear	= renderInfo.getColorClears()[colorClearNdx];
+			const UVec2			offset		= colorClear.getOffset();
+			const UVec2			size		= colorClear.getSize();
+			tcu::TextureLevel&	reference	= referenceAttachments[subpass.getColorAttachments()[colorClearNdx].getAttachment()];
+			VkClearValue		value;
+
+			value.color = colorClear.getColor();
+
+			clear(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), value);
+		}
+
+		if (renderInfo.getDepthStencilClear())
+		{
+			const DepthStencilClear&	dsClear		= *renderInfo.getDepthStencilClear();
+			const UVec2					offset		= dsClear.getOffset();
+			const UVec2					size		= dsClear.getSize();
+			tcu::TextureLevel&			reference	= referenceAttachments[subpass.getDepthStencilAttachment().getAttachment()];
+
+			if (tcu::hasDepthComponent(reference.getFormat().order))
+				clearDepth(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), dsClear.getDepth());
+
+			if (tcu::hasStencilComponent(reference.getFormat().order))
+				clearStencil(tcu::getSubregion(reference.getAccess(), offset.x(), offset.y(), 0, size.x(), size.y(), 1), dsClear.getStencil());
+		}
+
+		if (renderInfo.getRenderQuad())
+		{
+			const RenderQuad&	renderQuad	= *renderInfo.getRenderQuad();
+			const Vec4			posA		= renderQuad.getCornerA();
+			const Vec4			posB		= renderQuad.getCornerB();
+			const Vec2			origin		= Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
+			const Vec2			p			= Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
+			const IVec2			posAI		((deInt32)(origin.x() + (p.x() * posA.x())),
+											 (deInt32)(origin.y() + (p.y() * posA.y())));
+			const IVec2			posBI		((deInt32)(origin.x() + (p.x() * posB.x())),
+											 (deInt32)(origin.y() + (p.y() * posB.y())));
+
+			for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++)
+			{
+				const Attachment				attachment			= renderPassInfo.getAttachments()[subpass.getColorAttachments()[attachmentRefNdx].getAttachment()];
+				const tcu::TextureFormatInfo	textureInfo			= tcu::getTextureFormatInfo(mapVkFormat(attachment.getFormat()));
+				tcu::TextureLevel&				referenceTexture	= referenceAttachments[subpass.getColorAttachments()[attachmentRefNdx].getAttachment()];
+				const bool						srgb				= tcu::isSRGB(referenceTexture.getFormat());
+				const PixelBufferAccess	reference			= referenceTexture.getAccess();
+				const float						clampMin			= (float)(-MAX_INTEGER_VALUE);
+				const float						clampMax			= (float)(MAX_INTEGER_VALUE);
+				const Vec4						valueMax			(de::clamp(textureInfo.valueMax[0], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMax[1], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMax[2], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMax[3], clampMin, clampMax));
+
+				const Vec4						valueMin			(de::clamp(textureInfo.valueMin[0], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMin[1], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMin[2], clampMin, clampMax),
+																	 de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
+
+				DE_ASSERT(posAI.x() < posBI.x());
+				DE_ASSERT(posAI.y() < posBI.y());
+
+				for (int y = posAI.y(); y <= (int)posBI.y(); y++)
+				for (int x = posAI.x(); x <= (int)posBI.x(); x++)
+				{
+					const Vec4	uvs		= computeUvs(posAI, posBI, IVec2(x, y));
+					const Vec4	color	= valueMax * uvs + valueMin * (Vec4(1.0f) - uvs);
+
+					if (srgb)
+						reference.setPixel(tcu::linearToSRGB(color), x, y);
+					else
+						reference.setPixel(color, x, y);
+				}
+			}
+
+			if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
+			{
+				tcu::TextureLevel&				referenceTexture	= referenceAttachments[subpass.getDepthStencilAttachment().getAttachment()];
+				const PixelBufferAccess	reference			= referenceTexture.getAccess();
+
+				DE_ASSERT(posAI.x() < posBI.x());
+				DE_ASSERT(posAI.y() < posBI.y());
+
+				for (int y = posAI.y(); y <= (int)posBI.y(); y++)
+				for (int x = posAI.x(); x <= (int)posBI.x(); x++)
+				{
+					const Vec4 uvs = computeUvs(posAI, posBI, IVec2(x, y));
+
+					if (tcu::hasDepthComponent(reference.getFormat().order))
+						reference.setPixDepth(uvs.x(), x, y);
+
+					if (tcu::hasStencilComponent(reference.getFormat().order))
+						reference.setPixStencil(STENCIL_VALUE, x, y);
+				}
+			}
+		}
+	}
+
+	// Mark all attachments that were used but not stored as undefined
+	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
+	{
+		const Attachment				attachment	= renderPassInfo.getAttachments()[attachmentNdx];
+		const tcu::TextureFormat		format		= mapVkFormat(attachment.getFormat());
+		const tcu::TextureFormatInfo	textureInfo	= tcu::getTextureFormatInfo(format);
+		tcu::TextureLevel&				reference	= referenceAttachments[attachmentNdx];
+
+		if (attachmentUsed[attachmentNdx] && renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
+			tcu::fillWithGrid(tcu::getSubregion(reference.getAccess(), renderPos.x(), renderPos.y(), renderSize.x(), renderSize.y()), 2, textureInfo.valueMin, textureInfo.valueMax);
+	}
+}
+
+Maybe<deUint32> findColorAttachment (const Subpass&				subpass,
+									 deUint32					attachmentIndex)
+{
+	for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpass.getColorAttachments().size(); colorAttachmentNdx++)
+	{
+		if (subpass.getColorAttachments()[colorAttachmentNdx].getAttachment() == attachmentIndex)
+			return tcu::just((deUint32)colorAttachmentNdx);
+	}
+
+	return tcu::nothing<deUint32>();
+}
+
+int calcFloatDiff (float a, float b)
+{
+	const deUint32		au		= tcu::Float32(a).bits();
+	const deUint32		bu		= tcu::Float32(b).bits();
+
+	const bool			asign	= (au & (0x1u << 31u)) != 0u;
+	const bool			bsign	= (bu & (0x1u << 31u)) != 0u;
+
+	const deUint32		avalue	= (au & ((0x1u << 31u) - 1u));
+	const deUint32		bvalue	= (bu & ((0x1u << 31u) - 1u));
+
+	if (asign != bsign)
+		return avalue + bvalue + 1u;
+	else if (avalue < bvalue)
+		return bvalue - avalue;
+	else
+		return avalue - bvalue;
+}
+
+bool comparePixelToDepthClearValue (const ConstPixelBufferAccess&	access,
+									int								x,
+									int								y,
+									float							ref)
+{
+	const tcu::TextureFormat		format			= tcu::getEffectiveDepthStencilTextureFormat(access.getFormat(), tcu::Sampler::MODE_DEPTH);
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		{
+			const int	bitDepth	= tcu::getTextureFormatBitDepth(format).x();
+			const float	depth		= access.getPixDepth(x, y);
+			const float	threshold	= 2.0f / (float)((1 << bitDepth) - 1);
+
+			return deFloatAbs(depth - ref) <= threshold;
+		}
+
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+		{
+			const float	depth			= access.getPixDepth(x, y);
+			const int	mantissaBits	= tcu::getTextureFormatMantissaBitDepth(format).x();
+			const int	threshold		= 10 * 1 << (23 - mantissaBits);
+
+			DE_ASSERT(mantissaBits <= 23);
+
+			return calcFloatDiff(depth, ref) <= threshold;
+		}
+
+		default:
+			DE_FATAL("Invalid channel class");
+			return false;
+	}
+}
+
+bool comparePixelToStencilClearValue (const ConstPixelBufferAccess&	access,
+									  int							x,
+									  int							y,
+									  deUint32						ref)
+{
+	const deUint32 stencil = access.getPixStencil(x, y);
+
+	return stencil == ref;
+}
+
+bool comparePixelToColorClearValue (const ConstPixelBufferAccess&	access,
+									int								x,
+									int								y,
+									const VkClearColorValue&		ref)
+{
+	const tcu::TextureFormat		format			= access.getFormat();
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+	const BVec4						channelMask		= tcu::getTextureFormatChannelMask(format);
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		{
+			const IVec4	bitDepth	(tcu::getTextureFormatBitDepth(format));
+			const Vec4	resColor	(access.getPixel(x, y));
+			const Vec4	refColor	(ref.float32[0],
+									 ref.float32[1],
+									 ref.float32[2],
+									 ref.float32[3]);
+			const Vec4	threshold	(bitDepth[0] > 0 ? 20.0f / (float)((1 << bitDepth[0]) - 1) : 1.0f,
+									 bitDepth[1] > 0 ? 20.0f / (float)((1 << bitDepth[1]) - 1) : 1.0f,
+									 bitDepth[2] > 0 ? 20.0f / (float)((1 << bitDepth[2]) - 1) : 1.0f,
+									 bitDepth[3] > 0 ? 20.0f / (float)((1 << bitDepth[3]) - 1) : 1.0f);
+
+			if (tcu::isSRGB(access.getFormat()))
+				return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, tcu::linearToSRGB(refColor)), threshold), channelMask), channelMask));
+			else
+				return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
+		}
+
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+		{
+			const UVec4	resColor	(access.getPixelUint(x, y));
+			const UVec4	refColor	(ref.uint32[0],
+									 ref.uint32[1],
+									 ref.uint32[2],
+									 ref.uint32[3]);
+			const UVec4	threshold	(1);
+
+			return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
+		}
+
+		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+		{
+			const IVec4	resColor	(access.getPixelInt(x, y));
+			const IVec4	refColor	(ref.int32[0],
+									 ref.int32[1],
+									 ref.int32[2],
+									 ref.int32[3]);
+			const IVec4	threshold	(1);
+
+			return !(tcu::anyNotEqual(tcu::logicalAnd(lessThanEqual(tcu::absDiff(resColor, refColor), threshold), channelMask), channelMask));
+		}
+
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+		{
+			const Vec4	resColor		(access.getPixel(x, y));
+			const Vec4	refColor		(ref.float32[0],
+										 ref.float32[1],
+										 ref.float32[2],
+										 ref.float32[3]);
+			const IVec4	mantissaBits	(tcu::getTextureFormatMantissaBitDepth(format));
+			const IVec4	threshold		(10 * IVec4(1) << (23 - mantissaBits));
+
+			DE_ASSERT(tcu::allEqual(greaterThanEqual(threshold, IVec4(0)), BVec4(true)));
+
+			for (int ndx = 0; ndx < 4; ndx++)
+			{
+				if (calcFloatDiff(resColor[ndx], refColor[ndx]) > threshold[ndx] && channelMask[ndx])
+					return false;
+			}
+
+			return true;
+		}
+
+		default:
+			DE_FATAL("Invalid channel class");
+			return false;
+	}
+}
+
+class PixelStatus
+{
+public:
+	enum Status
+	{
+		STATUS_UNDEFINED	= 0,
+		STATUS_OK			= 1,
+		STATUS_FAIL			= 2,
+
+		STATUS_LAST
+	};
+
+			PixelStatus			(Status color, Status depth, Status stencil)
+		: m_status	((deUint8)(color << COLOR_OFFSET)
+					| (deUint8)((deUint8)depth << DEPTH_OFFSET)
+					| (deUint8)((deUint8)stencil << STENCIL_OFFSET))
+	{
+	}
+
+	Status	getColorStatus		(void) const { return (Status)((m_status & COLOR_MASK) >> COLOR_OFFSET); }
+	Status	getDepthStatus		(void) const { return (Status)((m_status & DEPTH_MASK) >> DEPTH_OFFSET); }
+	Status	getStencilStatus	(void) const { return (Status)((m_status & STENCIL_MASK) >> STENCIL_OFFSET); }
+
+	void	setColorStatus		(Status status)
+	{
+		DE_ASSERT(getColorStatus() == STATUS_UNDEFINED);
+		m_status |= ((deUint8)status) << COLOR_OFFSET;
+	}
+
+	void	setDepthStatus		(Status status)
+	{
+		DE_ASSERT(getDepthStatus() == STATUS_UNDEFINED);
+		m_status |= ((deUint8)status) << DEPTH_OFFSET;
+	}
+
+	void	setStencilStatus	(Status status)
+	{
+		DE_ASSERT(getStencilStatus() == STATUS_UNDEFINED);
+		m_status |= ((deUint8)status) << STENCIL_OFFSET;
+	}
+
+private:
+	enum
+	{
+		COLOR_OFFSET	= 0,
+		DEPTH_OFFSET	= 2,
+		STENCIL_OFFSET	= 4,
+
+		COLOR_MASK		= (3<<COLOR_OFFSET),
+		DEPTH_MASK		= (3<<DEPTH_OFFSET),
+		STENCIL_MASK	= (3<<STENCIL_OFFSET),
+	};
+	deUint8	m_status;
+};
+
+void checkDepthRenderQuad (const ConstPixelBufferAccess&	result,
+						   const IVec2&						posA,
+						   const IVec2&						posB,
+						   vector<PixelStatus>&				status)
+{
+	for (int y = posA.y(); y <= posB.y(); y++)
+	for (int x = posA.x(); x <= posB.x(); x++)
+	{
+		PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+		if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED)
+		{
+			const Vec4	minUvs		= computeUvs(posA, posB, IVec2(x-1, y-1));
+			const Vec4	maxUvs		= computeUvs(posA, posB, IVec2(x+1, y+1));
+			const bool	softCheck	= std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
+									|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
+			const float	resDepth	= result.getPixDepth(x, y);
+
+			if (resDepth >= minUvs.x() && resDepth <= maxUvs.x())
+				pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
+			else if (!softCheck)
+				pixelStatus.setDepthStatus(PixelStatus::STATUS_FAIL);
+		}
+	}
+}
+
+void checkStencilRenderQuad (const ConstPixelBufferAccess&		result,
+							 const IVec2&						posA,
+							 const IVec2&						posB,
+							 vector<PixelStatus>&				status)
+{
+	for (int y = posA.y(); y <= posB.y(); y++)
+	for (int x = posA.x(); x <= posB.x(); x++)
+	{
+		PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+		if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED)
+		{
+			const bool	softCheck	= std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
+									|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
+
+			if (result.getPixStencil(x, y) == STENCIL_VALUE)
+				pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
+			else if (!softCheck)
+				pixelStatus.setStencilStatus(PixelStatus::STATUS_FAIL);
+		}
+	}
+}
+
+void checkColorRenderQuad (const ConstPixelBufferAccess&	result,
+						   const IVec2&						posA,
+						   const IVec2&						posB,
+						   vector<PixelStatus>&				status)
+{
+	const tcu::TextureFormat&		format				= result.getFormat();
+	const bool						srgb				= tcu::isSRGB(format);
+	const tcu::TextureChannelClass	channelClass		= tcu::getTextureChannelClass(format.type);
+	const tcu::TextureFormatInfo	textureInfo			= tcu::getTextureFormatInfo(format);
+	const float						clampMin			= (float)(-MAX_INTEGER_VALUE);
+	const float						clampMax			= (float)(MAX_INTEGER_VALUE);
+	const Vec4						valueMax			(de::clamp(textureInfo.valueMax[0], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMax[1], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMax[2], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMax[3], clampMin, clampMax));
+
+	const Vec4						valueMin			(de::clamp(textureInfo.valueMin[0], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMin[1], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMin[2], clampMin, clampMax),
+														 de::clamp(textureInfo.valueMin[3], clampMin, clampMax));
+	const BVec4						channelMask			= tcu::getTextureFormatChannelMask(format);
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+		{
+			for (int y = posA.y(); y <= posB.y(); y++)
+			for (int x = posA.x(); x <= posB.x(); x++)
+			{
+				PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+				if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
+				{
+					const Vec4	minUvs		= computeUvs(posA, posB, IVec2(x-1, y-1));
+					const Vec4	maxUvs		= computeUvs(posA, posB, IVec2(x+1, y+1));
+					const bool	softCheck	= std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
+											|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
+
+					const Vec4	resColor	(result.getPixel(x, y));
+
+					const Vec4	minRefColor	= srgb ? tcu::linearToSRGB(valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs))
+													 : valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
+					const Vec4	maxRefColor	= srgb ? tcu::linearToSRGB(valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs))
+													 : valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
+
+					DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
+					DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
+					DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
+					DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
+
+					if (tcu::anyNotEqual(tcu::logicalAnd(
+											tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
+															lessThanEqual(resColor, maxRefColor)),
+											channelMask), channelMask))
+					{
+						if (!softCheck)
+							pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
+					}
+					else
+						pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+				}
+			}
+
+			break;
+		}
+
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+		{
+			for (int y = posA.y(); y <= posB.y(); y++)
+			for (int x = posA.x(); x <= posB.x(); x++)
+			{
+				PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+				if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
+				{
+					const Vec4	minUvs			= computeUvs(posA, posB, IVec2(x-1, y-1));
+					const Vec4	maxUvs			= computeUvs(posA, posB, IVec2(x+1, y+1));
+					const bool	softCheck		= std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
+												|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
+
+					const UVec4	resColor		(result.getPixelUint(x, y));
+
+					const Vec4	minRefColorF	= valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
+					const Vec4	maxRefColorF	= valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
+
+					const UVec4	minRefColor		(minRefColorF.asUint());
+					const UVec4	maxRefColor		(maxRefColorF.asUint());
+
+					DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
+					DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
+					DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
+					DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
+
+					if (tcu::anyNotEqual(tcu::logicalAnd(
+											tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
+															lessThanEqual(resColor, maxRefColor)),
+											channelMask), channelMask))
+					{
+						if (!softCheck)
+							pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
+					}
+					else
+						pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+				}
+			}
+
+			break;
+		}
+
+		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+		{
+			for (int y = posA.y(); y <= posB.y(); y++)
+			for (int x = posA.x(); x <= posB.x(); x++)
+			{
+				PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+				if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
+				{
+					const Vec4	minUvs			= computeUvs(posA, posB, IVec2(x-1, y-1));
+					const Vec4	maxUvs			= computeUvs(posA, posB, IVec2(x+1, y+1));
+					const bool	softCheck		= std::abs(x - posA.x()) <= 1 || std::abs(x - posB.x()) <= 1
+												|| std::abs(y - posA.y()) <= 1 || std::abs(y - posB.y()) <= 1;
+
+					const IVec4	resColor		(result.getPixelInt(x, y));
+
+					const Vec4	minRefColorF	= valueMax * minUvs + valueMin * (Vec4(1.0f) - minUvs);
+					const Vec4	maxRefColorF	= valueMax * maxUvs + valueMin * (Vec4(1.0f) - maxUvs);
+
+					const IVec4	minRefColor		(minRefColorF.asInt());
+					const IVec4	maxRefColor		(maxRefColorF.asInt());
+
+					DE_ASSERT(minRefColor[0] <= maxRefColor[0]);
+					DE_ASSERT(minRefColor[1] <= maxRefColor[1]);
+					DE_ASSERT(minRefColor[2] <= maxRefColor[2]);
+					DE_ASSERT(minRefColor[3] <= maxRefColor[3]);
+
+					if (tcu::anyNotEqual(tcu::logicalAnd(
+											tcu::logicalAnd(greaterThanEqual(resColor, minRefColor),
+															lessThanEqual(resColor, maxRefColor)),
+											channelMask), channelMask))
+					{
+						if (!softCheck)
+							pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
+					}
+					else
+						pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+				}
+			}
+
+			break;
+		}
+
+		default:
+			DE_FATAL("Invalid channel class");
+	}
+}
+
+void checkColorClear (const ConstPixelBufferAccess&	result,
+					  const UVec2&					offset,
+					  const UVec2&					size,
+					  vector<PixelStatus>&			status,
+					  const VkClearColorValue&		color)
+{
+	DE_ASSERT(offset.x() + size.x() <= (deUint32)result.getWidth());
+	DE_ASSERT(offset.y() + size.y() <= (deUint32)result.getHeight());
+
+	DE_ASSERT(result.getWidth() * result.getHeight() == (int)status.size());
+
+	for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
+	for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
+	{
+		PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+		DE_ASSERT(x + y * result.getWidth() < (int)status.size());
+
+		if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
+		{
+			if (comparePixelToColorClearValue(result, x, y, color))
+				pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+			else
+				pixelStatus.setColorStatus(PixelStatus::STATUS_FAIL);
+		}
+	}
+}
+
+void checkDepthClear (const ConstPixelBufferAccess&	result,
+					  const UVec2&					offset,
+					  const UVec2&					size,
+					  vector<PixelStatus>&			status,
+					  float							depth)
+{
+	for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
+	for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
+	{
+		PixelStatus&	pixelStatus	= status[x + y * result.getWidth()];
+
+		if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED)
+		{
+			if (comparePixelToDepthClearValue(result, x, y, depth))
+				pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
+			else
+				pixelStatus.setDepthStatus(PixelStatus::STATUS_FAIL);
+		}
+	}
+}
+
+void checkStencilClear (const ConstPixelBufferAccess&	result,
+						const UVec2&					offset,
+						const UVec2&					size,
+						vector<PixelStatus>&			status,
+						deUint32						stencil)
+{
+	for (int y = offset.y(); y < (int)(offset.y() + size.y()); y++)
+	for (int x = offset.x(); x < (int)(offset.x() + size.x()); x++)
+	{
+		PixelStatus&	pixelStatus	= status[x + y * result.getWidth()];
+
+		if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED)
+		{
+			if (comparePixelToStencilClearValue(result, x, y, stencil))
+				pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
+			else
+				pixelStatus.setStencilStatus(PixelStatus::STATUS_FAIL);
+		}
+	}
+}
+
+bool verifyAttachment (const ConstPixelBufferAccess&		result,
+					   const Maybe<ConstPixelBufferAccess>&	secondaryResult,
+					   const RenderPass&					renderPassInfo,
+					   const Maybe<VkClearValue>&			renderPassClearValue,
+					   const Maybe<VkClearValue>&			imageClearValue,
+					   const vector<Subpass>&				subpasses,
+					   const vector<SubpassRenderInfo>&		subpassRenderInfo,
+					   const PixelBufferAccess&				errorImage,
+					   deUint32								attachmentIndex,
+					   const UVec2&							renderPos,
+					   const UVec2&							renderSize)
+{
+	const tcu::TextureFormat&		format				= result.getFormat();
+	const bool						hasDepth			= tcu::hasDepthComponent(format.order);
+	const bool						hasStencil			= tcu::hasStencilComponent(format.order);
+	const bool						isColorFormat		= !hasDepth && !hasStencil;
+	const PixelStatus				initialStatus		(isColorFormat ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK,
+														 hasDepth ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK,
+														 hasStencil ? PixelStatus::STATUS_UNDEFINED : PixelStatus::STATUS_OK);
+
+	bool							attachmentIsUsed	= false;
+	vector<PixelStatus>				status				(result.getWidth() * result.getHeight(), initialStatus);
+	tcu::clear(errorImage, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
+
+	// Check if attachment is used
+	for (int subpassNdx = 0; subpassNdx < (int)subpasses.size(); subpassNdx++)
+	{
+		const Subpass&			subpass			= subpasses[subpassNdx];
+		const Maybe<deUint32>	attachmentNdx	= findColorAttachment(subpass, attachmentIndex);
+
+		if (attachmentNdx || subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex)
+			attachmentIsUsed = true;
+	}
+
+	// Set all pixels that have undefined values to OK
+	if (attachmentIsUsed && (((isColorFormat || hasDepth) && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
+							|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)))
+	{
+		for(int y = renderPos.y(); y < (int)(renderPos.y() + renderSize.y()); y++)
+		for(int x = renderPos.x(); x < (int)(renderPos.x() + renderSize.x()); x++)
+		{
+			PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+			if (isColorFormat && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
+				pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+			else
+			{
+				if (hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
+					pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
+
+				if (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE)
+					pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
+			}
+		}
+	}
+
+	// Check renderpass rendering results
+	if (renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE
+		|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE))
+	{
+		// Check subpass rendering results
+		for (int subpassNdx = (int)subpasses.size() - 1; subpassNdx >= 0; subpassNdx--)
+		{
+			const Subpass&				subpass			= subpasses[subpassNdx];
+			const SubpassRenderInfo&	renderInfo		= subpassRenderInfo[subpassNdx];
+			const Maybe<deUint32>		attachmentNdx	= findColorAttachment(subpass, attachmentIndex);
+
+			// Check rendered quad
+			if (renderInfo.getRenderQuad() && (attachmentNdx || subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex))
+			{
+				const RenderQuad&	renderQuad	= *renderInfo.getRenderQuad();
+				const Vec4			posA		= renderQuad.getCornerA();
+				const Vec4			posB		= renderQuad.getCornerB();
+				const Vec2			origin		= Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
+				const Vec2			p			= Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f);
+				const IVec2			posAI		((deInt32)(origin.x() + (p.x() * posA.x())),
+												 (deInt32)(origin.y() + (p.y() * posA.y())));
+				const IVec2			posBI		((deInt32)(origin.x() + (p.x() * posB.x())),
+												 (deInt32)(origin.y() + (p.y() * posB.y())));
+
+				if (isColorFormat)
+					checkColorRenderQuad(result, posAI, posBI, status);
+				else
+				{
+					if (hasDepth)
+						checkDepthRenderQuad(result, posAI, posBI, status);
+
+					if (hasDepth && hasStencil)
+						checkStencilRenderQuad(*secondaryResult, posAI, posBI, status);
+					else if (hasStencil)
+						checkStencilRenderQuad(result, posAI, posBI, status);
+				}
+			}
+
+			// Check color attachment clears
+			if (attachmentNdx && !renderInfo.getColorClears().empty())
+			{
+				const ColorClear& clear = renderInfo.getColorClears()[*attachmentNdx];
+
+				checkColorClear(result, clear.getOffset(), clear.getSize(), status, clear.getColor());
+			}
+
+			// Check depth/stencil attachment clears
+			if (subpass.getDepthStencilAttachment().getAttachment() == attachmentIndex && renderInfo.getDepthStencilClear())
+			{
+				const DepthStencilClear clear = *renderInfo.getDepthStencilClear();
+
+				if (hasDepth)
+					checkDepthClear(result, clear.getOffset(), clear.getSize(), status, clear.getDepth());
+
+				if (hasDepth && hasStencil)
+					checkStencilClear(*secondaryResult, clear.getOffset(), clear.getSize(), status, clear.getStencil());
+				else if (hasStencil)
+					checkStencilClear(result, clear.getOffset(), clear.getSize(), status, clear.getStencil());
+			}
+		}
+
+		// Check renderpas clear results
+		if (attachmentIsUsed && renderPassClearValue)
+		{
+			if (isColorFormat)
+			{
+				if (renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+					checkColorClear(result, renderPos, renderSize, status, renderPassClearValue->color);
+			}
+			else
+			{
+				if (hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+					checkDepthClear(result, renderPos, renderSize, status, renderPassClearValue->depthStencil.depth);
+
+				if (hasDepth && hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+					checkStencilClear(*secondaryResult, renderPos, renderSize, status, renderPassClearValue->depthStencil.stencil);
+				else if (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+					checkStencilClear(result, renderPos, renderSize, status, renderPassClearValue->depthStencil.stencil);
+			}
+		}
+	}
+
+	// Set all pixels that have undefined values fater renderpass to OK
+	if (attachmentIsUsed && (((isColorFormat || hasDepth) && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+							|| (hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)))
+	{
+		for(int y = renderPos.y(); y < (int)(renderPos.y() + renderSize.y()); y++)
+		for(int x = renderPos.x(); x < (int)(renderPos.x() + renderSize.x()); x++)
+		{
+			PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+			if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED
+				&& isColorFormat && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+				pixelStatus.setColorStatus(PixelStatus::STATUS_OK);
+			else
+			{
+				if (pixelStatus.getDepthStatus() == PixelStatus::STATUS_UNDEFINED
+					&& hasDepth && renderPassInfo.getAttachments()[attachmentIndex].getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+					pixelStatus.setDepthStatus(PixelStatus::STATUS_OK);
+
+				if (pixelStatus.getStencilStatus() == PixelStatus::STATUS_UNDEFINED
+					&& hasStencil && renderPassInfo.getAttachments()[attachmentIndex].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+					pixelStatus.setStencilStatus(PixelStatus::STATUS_OK);
+			}
+		}
+	}
+
+	if (imageClearValue)
+	{
+		if (isColorFormat)
+			checkColorClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->color);
+		else
+		{
+			if (hasDepth)
+				checkDepthClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->depthStencil.depth);
+
+			if (hasDepth && hasStencil)
+				checkStencilClear(*secondaryResult, UVec2(0, 0), UVec2(secondaryResult->getWidth(), result.getHeight()), status, imageClearValue->depthStencil.stencil);
+			else if (hasStencil)
+				checkStencilClear(result, UVec2(0, 0), UVec2(result.getWidth(), result.getHeight()), status, imageClearValue->depthStencil.stencil);
+		}
+	}
+
+	{
+		bool isOk = true;
+
+		for(int y = 0; y < result.getHeight(); y++)
+		for(int x = 0; x < result.getWidth(); x++)
+		{
+			const PixelStatus& pixelStatus = status[x + y * result.getWidth()];
+
+			if (isColorFormat)
+			{
+				if (pixelStatus.getColorStatus() != PixelStatus::STATUS_OK)
+				{
+					if (pixelStatus.getColorStatus() == PixelStatus::STATUS_UNDEFINED)
+						errorImage.setPixel(Vec4(1.0f, 1.0f, 0.0f, 1.0f), x, y);
+					else if (pixelStatus.getColorStatus() == PixelStatus::STATUS_FAIL)
+						errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
+
+					isOk = false;
+				}
+			}
+			else
+			{
+				if (hasDepth && pixelStatus.getDepthStatus() != PixelStatus::STATUS_OK)
+				{
+					errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
+					isOk = false;
+				}
+
+				if (hasStencil && pixelStatus.getStencilStatus() != PixelStatus::STATUS_OK)
+				{
+					errorImage.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y);
+					isOk = false;
+				}
+			}
+		}
+
+		return isOk;
+	}
+}
+
+bool logAndVerifyImages (TestLog&											log,
+						 const DeviceInterface&								vk,
+						 VkDevice											device,
+						 const vector<de::SharedPtr<AttachmentResources> >&	attachmentResources,
+						 const vector<bool>&								attachmentIsLazy,
+						 const RenderPass&									renderPassInfo,
+						 const vector<Maybe<VkClearValue> >&				renderPassClearValues,
+						 const vector<Maybe<VkClearValue> >&				imageClearValues,
+						 const vector<SubpassRenderInfo>&					subpassRenderInfo,
+						 const UVec2&										targetSize,
+						 const TestConfig&									config)
+{
+	vector<tcu::TextureLevel>	referenceAttachments;
+	bool						isOk					= true;
+
+	log << TestLog::Message << "Reference images fill undefined pixels with grid pattern." << TestLog::EndMessage;
+
+	renderReferenceImages(referenceAttachments, renderPassInfo, targetSize, imageClearValues, renderPassClearValues, subpassRenderInfo, config.renderPos, config.renderSize);
+
+	for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
+	{
+		if (!attachmentIsLazy[attachmentNdx])
+		{
+			const Attachment			attachment		= renderPassInfo.getAttachments()[attachmentNdx];
+			const tcu::TextureFormat	format			= mapVkFormat(attachment.getFormat());
+
+			if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order))
+			{
+				const tcu::TextureFormat	depthFormat		= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
+				const VkDeviceSize			depthBufferSize	= targetSize.x() * targetSize.y() * depthFormat.getPixelSize();
+				void* const					depthPtr		= attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
+
+				const tcu::TextureFormat	stencilFormat		= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
+				const VkDeviceSize			stencilBufferSize	= targetSize.x() * targetSize.y() * stencilFormat.getPixelSize();
+				void* const					stencilPtr			= attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
+
+				const VkMappedMemoryRange	ranges[] =
+				{
+					{
+						VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,								// sType;
+						DE_NULL,															// pNext;
+						attachmentResources[attachmentNdx]->getResultMemory().getMemory(),	// mem;
+						attachmentResources[attachmentNdx]->getResultMemory().getOffset(),	// offset;
+						depthBufferSize														// size;
+					},
+					{
+						VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,										// sType;
+						DE_NULL,																	// pNext;
+						attachmentResources[attachmentNdx]->getSecondaryResultMemory().getMemory(),	// mem;
+						attachmentResources[attachmentNdx]->getSecondaryResultMemory().getOffset(),	// offset;
+						stencilBufferSize															// size;
+					}
+				};
+				VK_CHECK(vk.invalidateMappedMemoryRanges(device, 2u, ranges));
+
+				{
+					const ConstPixelBufferAccess	depthAccess		(depthFormat, targetSize.x(), targetSize.y(), 1, depthPtr);
+					const ConstPixelBufferAccess	stencilAccess	(stencilFormat, targetSize.x(), targetSize.y(), 1, stencilPtr);
+					tcu::TextureLevel				errorImage		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
+
+					log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Depth", "Attachment " + de::toString(attachmentNdx) + " Depth", depthAccess);
+					log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Stencil", "Attachment " + de::toString(attachmentNdx) + " Stencil", stencilAccess);
+
+					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
+
+					if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
+						&& !verifyAttachment(depthAccess, tcu::just(stencilAccess), renderPassInfo, renderPassClearValues[attachmentNdx], imageClearValues[attachmentNdx], renderPassInfo.getSubpasses(), subpassRenderInfo, errorImage.getAccess(), (deUint32)attachmentNdx, config.renderPos, config.renderSize))
+					{
+						log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
+						isOk = false;
+					}
+				}
+			}
+			else
+			{
+				const VkDeviceSize			bufferSize	= targetSize.x() * targetSize.y() * format.getPixelSize();
+				void* const					ptr			= attachmentResources[attachmentNdx]->getResultMemory().getHostPtr();
+
+				const VkMappedMemoryRange	range	=
+				{
+					VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,								// sType;
+					DE_NULL,															// pNext;
+					attachmentResources[attachmentNdx]->getResultMemory().getMemory(),	// mem;
+					attachmentResources[attachmentNdx]->getResultMemory().getOffset(),	// offset;
+					bufferSize															// size;
+				};
+				VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1u, &range));
+
+				{
+					const ConstPixelBufferAccess	access		(format, targetSize.x(), targetSize.y(), 1, ptr);
+					tcu::TextureLevel				errorImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y());
+
+					log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access);
+					log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess());
+
+					if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE)
+						&& !verifyAttachment(access, tcu::nothing<ConstPixelBufferAccess>(), renderPassInfo, renderPassClearValues[attachmentNdx], imageClearValues[attachmentNdx], renderPassInfo.getSubpasses(), subpassRenderInfo, errorImage.getAccess(), (deUint32)attachmentNdx, config.renderPos, config.renderSize))
+					{
+						log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess());
+						isOk = false;
+					}
+				}
+			}
+		}
+	}
+
+	return isOk;
+}
+
+std::string getAttachmentType (VkFormat vkFormat)
+{
+	const tcu::TextureFormat		format			= mapVkFormat(vkFormat);
+	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(format.type);
+
+	switch (channelClass)
+	{
+		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+			return "ivec4";
+
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+			return "uvec4";
+
+		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+			return "vec4";
+
+		default:
+			DE_FATAL("Unknown channel class");
+			return "";
+	}
+}
+
+void createTestShaders (SourceCollections& dst, TestConfig config)
+{
+	if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
+	{
+		const vector<Subpass>&	subpasses	= config.renderPass.getSubpasses();
+
+		for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
+		{
+			const Subpass&		subpass		= subpasses[subpassNdx];
+			std::ostringstream	vertexShader;
+			std::ostringstream	fragmentShader;
+
+			vertexShader << "#version 310 es\n"
+						 << "layout(location = 0) in highp vec4 a_position;\n"
+						 << "layout(location = 0) out highp vec2 v_color;\n"
+						 << "void main (void) {\n"
+						 << "\thighp float a = 0.5 + a_position.x;\n"
+						 << "\thighp float b = 0.5 + a_position.y;\n"
+						 << "\tv_color = vec2(a, b);\n"
+						 << "\tgl_Position = a_position;\n"
+						 << "}\n";
+
+			fragmentShader << "#version 310 es\n"
+						   << "layout(location = 0) in highp vec2 v_color;\n";
+
+			for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
+			{
+				const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
+				fragmentShader << "layout(location = " << attachmentNdx << ") out highp " << attachmentType << " o_color" << attachmentNdx << ";\n";
+			}
+
+			fragmentShader	<< "void main (void) {\n"
+							<< "\thighp vec4 scale = vec4(v_color.x, v_color.y, v_color.x * v_color.y, (v_color.x + v_color.y) / 2.0);\n";
+
+			for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++)
+			{
+				const tcu::TextureFormat		format			= mapVkFormat(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
+				const tcu::TextureFormatInfo	formatInfo		= tcu::getTextureFormatInfo(format);
+				const float						clampMin		= (float)(-MAX_INTEGER_VALUE);
+				const float						clampMax		= (float)(MAX_INTEGER_VALUE);
+				const Vec4						valueMax		(de::clamp(formatInfo.valueMax[0], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMax[1], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMax[2], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMax[3], clampMin, clampMax));
+
+				const Vec4						valueMin		(de::clamp(formatInfo.valueMin[0], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMin[1], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMin[2], clampMin, clampMax),
+																 de::clamp(formatInfo.valueMin[3], clampMin, clampMax));
+				const std::string				attachmentType	= getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat());
+
+				fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(vec4" << valueMin << " + vec4" << (valueMax - valueMin)  << " * scale);\n";
+			}
+
+			fragmentShader << "}\n";
+
+			dst.glslSources.add(de::toString(subpassNdx) + "-vert") << glu::VertexSource(vertexShader.str());
+			dst.glslSources.add(de::toString(subpassNdx) + "-frag") << glu::FragmentSource(fragmentShader.str());
+		}
+	}
+}
+
+void initializeAttachmentIsLazy (vector<bool>& attachmentIsLazy, const vector<Attachment>& attachments, TestConfig::ImageMemory imageMemory)
+{
+	bool lastAttachmentWasLazy = false;
+
+	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
+	{
+		if (attachments[attachmentNdx].getLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
+			&& attachments[attachmentNdx].getStoreOp() != VK_ATTACHMENT_STORE_OP_STORE
+			&& attachments[attachmentNdx].getStencilLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD
+			&& attachments[attachmentNdx].getStencilStoreOp() != VK_ATTACHMENT_STORE_OP_STORE)
+		{
+			if (imageMemory == TestConfig::IMAGEMEMORY_LAZY || (imageMemory & TestConfig::IMAGEMEMORY_LAZY && !lastAttachmentWasLazy))
+			{
+				attachmentIsLazy.push_back(true);
+				lastAttachmentWasLazy = true;
+			}
+			else if (imageMemory & TestConfig::IMAGEMEMORY_STRICT)
+			{
+				attachmentIsLazy.push_back(false);
+				lastAttachmentWasLazy = false;
+			}
+			else
+				DE_FATAL("Unknown imageMemory");
+		}
+		else
+			attachmentIsLazy.push_back(false);
+	}
+}
+
+void initializeSubpassIsSecondary (vector<bool>& subpassIsSecondary, const vector<Subpass>& subpasses, TestConfig::CommandBufferTypes commandBuffer)
+{
+	bool lastSubpassWasSecondary = false;
+
+	for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
+	{
+		if (commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY || (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary))
+		{
+			subpassIsSecondary.push_back(true);
+			lastSubpassWasSecondary = true;
+		}
+		else if (commandBuffer & TestConfig::COMMANDBUFFERTYPES_INLINE)
+		{
+			subpassIsSecondary.push_back(false);
+			lastSubpassWasSecondary = false;
+		}
+		else
+			DE_FATAL("Unknown commandBuffer");
+	}
+}
+
+void initializeImageClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments, const vector<bool>& isLazy)
+{
+	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
+	{
+		if (!isLazy[attachmentNdx])
+			clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
+		else
+			clearValues.push_back(nothing<VkClearValue>());
+	}
+}
+
+void initializeRenderPassClearValues (de::Random& rng, vector<Maybe<VkClearValue> >& clearValues, const vector<Attachment>& attachments)
+{
+	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
+	{
+		if (attachments[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR
+			|| attachments[attachmentNdx].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR)
+		{
+			clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng)));
+		}
+		else
+			clearValues.push_back(nothing<VkClearValue>());
+	}
+}
+
+void initializeSubpassClearValues (de::Random& rng, vector<vector<VkClearColorValue> >& clearValues, const RenderPass& renderPass)
+{
+	clearValues.resize(renderPass.getSubpasses().size());
+
+	for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
+	{
+		const Subpass&						subpass				= renderPass.getSubpasses()[subpassNdx];
+		const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
+
+		clearValues[subpassNdx].resize(colorAttachments.size());
+
+		for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
+		{
+			const AttachmentReference&	attachmentRef	= colorAttachments[attachmentRefNdx];
+			const Attachment&			attachment		= renderPass.getAttachments()[attachmentRef.getAttachment()];
+
+			clearValues[subpassNdx][attachmentRefNdx] = randomColorClearValue(attachment, rng);
+		}
+	}
+}
+
+void logSubpassRenderInfo (TestLog&					log,
+						   const SubpassRenderInfo&	info)
+{
+	log << TestLog::Message << "Viewport, offset: " << info.getViewportOffset() << ", size: " << info.getViewportSize() << TestLog::EndMessage;
+
+	if (info.isSecondary())
+		log << TestLog::Message << "Subpass uses secondary command buffers" << TestLog::EndMessage;
+	else
+		log << TestLog::Message << "Subpass uses inlined commands" << TestLog::EndMessage;
+
+	for (deUint32 attachmentNdx = 0; attachmentNdx < info.getColorClears().size(); attachmentNdx++)
+	{
+		const ColorClear&	colorClear	= info.getColorClears()[attachmentNdx];
+
+		log << TestLog::Message << "Clearing color attachment " << attachmentNdx
+			<< ". Offset: " << colorClear.getOffset()
+			<< ", Size: " << colorClear.getSize()
+			<< ", Color: " << clearColorToString(info.getColorAttachment(attachmentNdx).getFormat(), colorClear.getColor()) << TestLog::EndMessage;
+	}
+
+	if (info.getDepthStencilClear())
+	{
+		const DepthStencilClear&	depthStencilClear	= *info.getDepthStencilClear();
+
+		log << TestLog::Message << "Clearing depth stencil attachment"
+			<< ". Offset: " << depthStencilClear.getOffset()
+			<< ", Size: " << depthStencilClear.getSize()
+			<< ", Depth: " << depthStencilClear.getDepth()
+			<< ", Stencil: " << depthStencilClear.getStencil() << TestLog::EndMessage;
+	}
+
+	if (info.getRenderQuad())
+	{
+		const RenderQuad&	renderQuad	= *info.getRenderQuad();
+
+		log << TestLog::Message << "Rendering gradient quad to " << renderQuad.getCornerA() << " -> " << renderQuad.getCornerB() << TestLog::EndMessage;
+	}
+}
+
+void logTestCaseInfo (TestLog&									log,
+					  const TestConfig&							config,
+					  const vector<bool>&						attachmentIsLazy,
+					  const vector<Maybe<VkClearValue> >&		imageClearValues,
+					  const vector<Maybe<VkClearValue> >&		renderPassClearValues,
+					  const vector<SubpassRenderInfo>&			subpassRenderInfo)
+{
+	const RenderPass&	renderPass	= config.renderPass;
+
+	logRenderPassInfo(log, renderPass);
+
+	DE_ASSERT(attachmentIsLazy.size() == renderPass.getAttachments().size());
+	DE_ASSERT(imageClearValues.size() == renderPass.getAttachments().size());
+	DE_ASSERT(renderPassClearValues.size() == renderPass.getAttachments().size());
+
+	log << TestLog::Message << "TargetSize: " << config.targetSize << TestLog::EndMessage;
+	log << TestLog::Message << "Render area, Offset: " << config.renderPos << ", Size: " << config.renderSize << TestLog::EndMessage;
+
+	for (size_t attachmentNdx = 0; attachmentNdx < attachmentIsLazy.size(); attachmentNdx++)
+	{
+		const tcu::ScopedLogSection	section	(log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx));
+
+		if (attachmentIsLazy[attachmentNdx])
+			log << TestLog::Message << "Is lazy." << TestLog::EndMessage;
+
+		if (imageClearValues[attachmentNdx])
+			log << TestLog::Message << "Image is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *imageClearValues[attachmentNdx]) << " before rendering." << TestLog::EndMessage;
+
+		if (renderPass.getAttachments()[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR && renderPassClearValues[attachmentNdx])
+			log << TestLog::Message << "Attachment is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *renderPassClearValues[attachmentNdx]) << " in the beginning of the render pass." << TestLog::EndMessage;
+	}
+
+	for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++)
+	{
+		const tcu::ScopedLogSection section (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx));
+
+		logSubpassRenderInfo(log, subpassRenderInfo[subpassNdx]);
+	}
+}
+
+void initializeSubpassRenderInfo (vector<SubpassRenderInfo>& renderInfos, de::Random& rng, const RenderPass& renderPass, const TestConfig& config)
+{
+	const TestConfig::CommandBufferTypes	commandBuffer			= config.commandBufferTypes;
+	const vector<Subpass>&					subpasses				= renderPass.getSubpasses();
+	bool									lastSubpassWasSecondary	= false;
+
+	for (deUint32 subpassNdx = 0; subpassNdx < (deUint32)subpasses.size(); subpassNdx++)
+	{
+		const Subpass&				subpass				= subpasses[subpassNdx];
+		const bool					subpassIsSecondary	= commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY
+														|| (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary) ? true : false;
+		const UVec2					viewportSize		((config.renderSize * UVec2(2)) / UVec2(3));
+		const UVec2					viewportOffset		(config.renderPos.x() + (subpassNdx % 2) * (config.renderSize.x() / 3),
+														 config.renderPos.y() + ((subpassNdx / 2) % 2) * (config.renderSize.y() / 3));
+
+		vector<ColorClear>			colorClears;
+		Maybe<DepthStencilClear>	depthStencilClear;
+		Maybe<RenderQuad>			renderQuad;
+
+		lastSubpassWasSecondary		= subpassIsSecondary;
+
+		if (config.renderTypes & TestConfig::RENDERTYPES_CLEAR)
+		{
+			const vector<AttachmentReference>&	colorAttachments	= subpass.getColorAttachments();
+
+			for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++)
+			{
+				const AttachmentReference&	attachmentRef	= colorAttachments[attachmentRefNdx];
+				const Attachment&			attachment		= renderPass.getAttachments()[attachmentRef.getAttachment()];
+				const UVec2					size			((viewportSize * UVec2(2)) / UVec2(3));
+				const UVec2					offset			(viewportOffset.x() + ((deUint32)attachmentRefNdx % 2u) * (viewportSize.x() / 3u),
+															 viewportOffset.y() + (((deUint32)attachmentRefNdx / 2u) % 2u) * (viewportSize.y() / 3u));
+				const VkClearColorValue		color			= randomColorClearValue(attachment, rng);
+
+				colorClears.push_back(ColorClear(offset, size, color));
+			}
+
+			if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED)
+			{
+				const Attachment&	attachment		= renderPass.getAttachments()[subpass.getDepthStencilAttachment().getAttachment()];
+				const UVec2			size			((viewportSize * UVec2(2)) / UVec2(3));
+				const UVec2			offset			(viewportOffset.x() + ((deUint32)colorAttachments.size() % 2u) * (viewportSize.x() / 3u),
+													 viewportOffset.y() + (((deUint32)colorAttachments.size() / 2u) % 2u) * (viewportSize.y() / 3u));
+				const VkClearValue	value			= randomClearValue(attachment, rng);
+
+				depthStencilClear = tcu::just(DepthStencilClear(offset, size, value.depthStencil.depth, value.depthStencil.stencil));
+			}
+		}
+
+		if (config.renderTypes & TestConfig::RENDERTYPES_DRAW)
+			renderQuad = tcu::just(RenderQuad(tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), tcu::Vec4(0.5f, 0.5f, 1.0f, 1.0f)));
+
+		renderInfos.push_back(SubpassRenderInfo(renderPass, subpassNdx, subpassIsSecondary, viewportOffset, viewportSize, renderQuad, colorClears, depthStencilClear));
+	}
+}
+
+void checkTextureFormatSupport (TestLog&					log,
+								const InstanceInterface&	vk,
+								VkPhysicalDevice			device,
+								const vector<Attachment>&	attachments)
+{
+	bool supported = true;
+
+	for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++)
+	{
+		const Attachment&			attachment					= attachments[attachmentNdx];
+		const tcu::TextureFormat	format						= mapVkFormat(attachment.getFormat());
+		const bool					isDepthOrStencilAttachment	= hasDepthComponent(format.order) || hasStencilComponent(format.order);
+		const VkFormatFeatureFlags	flags						= isDepthOrStencilAttachment? VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+		VkFormatProperties			properties;
+
+		VK_CHECK(vk.getPhysicalDeviceFormatProperties(device, attachment.getFormat(), &properties));
+
+		if ((properties.optimalTilingFeatures & flags) != flags)
+		{
+			supported = false;
+			log << TestLog::Message << "Format: " << attachment.getFormat() << " not supported as " << (isDepthOrStencilAttachment ? "depth stencil attachment" : "color attachment") << TestLog::EndMessage;
+		}
+	}
+
+	if (!supported)
+		TCU_THROW(NotSupportedError, "Format not supported");
+}
+
+tcu::TestStatus renderPassTest (Context& context, TestConfig config)
+{
+	const UVec2							targetSize			= config.targetSize;
+	const UVec2							renderPos			= config.renderPos;
+	const UVec2							renderSize			= config.renderSize;
+	const RenderPass&					renderPassInfo		= config.renderPass;
+
+	TestLog&							log					= context.getTestContext().getLog();
+	de::Random							rng					(config.seed);
+
+	vector<bool>						attachmentIsLazy;
+	vector<Maybe<VkClearValue> >		imageClearValues;
+	vector<Maybe<VkClearValue> >		renderPassClearValues;
+
+	vector<bool>						subpassIsSecondary;
+	vector<SubpassRenderInfo>			subpassRenderInfo;
+	vector<vector<VkClearColorValue> >	subpassColorClearValues;
+
+	initializeAttachmentIsLazy(attachmentIsLazy, renderPassInfo.getAttachments(), config.imageMemory);
+	initializeImageClearValues(rng, imageClearValues, renderPassInfo.getAttachments(), attachmentIsLazy);
+	initializeRenderPassClearValues(rng, renderPassClearValues, renderPassInfo.getAttachments());
+
+	initializeSubpassIsSecondary(subpassIsSecondary, renderPassInfo.getSubpasses(), config.commandBufferTypes);
+	initializeSubpassClearValues(rng, subpassColorClearValues, renderPassInfo);
+	initializeSubpassRenderInfo(subpassRenderInfo, rng, renderPassInfo, config);
+
+	logTestCaseInfo(log, config, attachmentIsLazy, imageClearValues, renderPassClearValues, subpassRenderInfo);
+
+	checkTextureFormatSupport(log, context.getInstanceInterface(), context.getPhysicalDevice(), config.renderPass.getAttachments());
+
+	{
+		const VkDevice								device								= context.getDevice();
+		const DeviceInterface&						vk									= context.getDeviceInterface();
+		const VkQueue								queue								= context.getUniversalQueue();
+		const deUint32								queueIndex							= context.getUniversalQueueFamilyIndex();
+		Allocator&									allocator							= context.getDefaultAllocator();
+
+		const Unique<VkRenderPass>					renderPass							(createRenderPass(vk, device, renderPassInfo));
+		const Unique<VkCmdPool>						commandBufferPool					(createCommandPool(vk, device, queueIndex, 0));
+		const Unique<VkCmdBuffer>					initializeImagesCommandBuffer		(createCommandBuffer(vk, device, *commandBufferPool, VK_CMD_BUFFER_LEVEL_PRIMARY, 0u));
+		const Unique<VkCmdBuffer>					renderCommandBuffer					(createCommandBuffer(vk, device, *commandBufferPool, VK_CMD_BUFFER_LEVEL_PRIMARY, 0u));
+		const Unique<VkCmdBuffer>					readImagesToBuffersCommandBuffer	(createCommandBuffer(vk, device, *commandBufferPool, VK_CMD_BUFFER_LEVEL_PRIMARY, 0u));
+
+		vector<de::SharedPtr<AttachmentResources> >	attachmentResources;
+		vector<de::SharedPtr<SubpassRenderer> >		subpassRenderers;
+		vector<VkImageView>							attachmentViews;
+
+		for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++)
+		{
+			const Attachment&	attachmentInfo	= renderPassInfo.getAttachments()[attachmentNdx];
+
+			attachmentResources.push_back(de::SharedPtr<AttachmentResources>(new AttachmentResources(vk, device, allocator, queueIndex, targetSize, attachmentInfo, attachmentIsLazy[attachmentNdx])));
+			attachmentViews.push_back(attachmentResources[attachmentNdx]->getAttachmentView());
+		}
+
+		beginCommandBuffer(vk, *initializeImagesCommandBuffer, 0, DE_NULL, 0, DE_NULL);
+		pushImageInitializationCommands(vk, *initializeImagesCommandBuffer, renderPassInfo.getAttachments(), attachmentResources, queueIndex, imageClearValues);
+		endCommandBuffer(vk, *initializeImagesCommandBuffer);
+
+		{
+			const Unique<VkFramebuffer> framebuffer (createFramebuffer(vk, device, *renderPass, targetSize, attachmentViews));
+
+			for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++)
+				subpassRenderers.push_back(de::SharedPtr<SubpassRenderer>(new SubpassRenderer(context, vk, device, allocator, *renderPass, *framebuffer, *commandBufferPool, queueIndex, subpassRenderInfo[subpassNdx])));
+
+			beginCommandBuffer(vk, *renderCommandBuffer, 0, DE_NULL, 0, DE_NULL);
+			pushRenderPassCommands(vk, *renderCommandBuffer, *renderPass, *framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, config.renderTypes);
+			endCommandBuffer(vk, *renderCommandBuffer);
+
+			beginCommandBuffer(vk, *readImagesToBuffersCommandBuffer, 0, DE_NULL, 0, DE_NULL);
+			pushReadImagesToBuffers(vk, *readImagesToBuffersCommandBuffer, queueIndex, attachmentResources, renderPassInfo.getAttachments(), attachmentIsLazy, targetSize);
+			endCommandBuffer(vk, *readImagesToBuffersCommandBuffer);
+			{
+				const VkCmdBuffer commandBuffers[] =
+				{
+					*initializeImagesCommandBuffer,
+					*renderCommandBuffer,
+					*readImagesToBuffersCommandBuffer
+				};
+				const Unique<VkFence>	fence		(createFence(vk, device, 0u));
+
+				queueSubmit(vk, queue, DE_LENGTH_OF_ARRAY(commandBuffers), commandBuffers, *fence);
+				waitForFences(vk, device, 1, &fence.get(), VK_TRUE, ~0ull);
+			}
+		}
+
+		if (logAndVerifyImages(log, vk, device, attachmentResources, attachmentIsLazy, renderPassInfo, renderPassClearValues, imageClearValues, subpassRenderInfo, targetSize, config))
+			return tcu::TestStatus::pass("Pass");
+		else
+			return tcu::TestStatus::fail("Result verification failed");
+	}
+}
+
+// \todo Fill with actually required formats in the future
+static const VkFormat s_colorFormats[] =
+{
+	VK_FORMAT_R5G6B5_UNORM,
+	VK_FORMAT_R5G5B5A1_UNORM,
+	VK_FORMAT_R8_UNORM,
+	VK_FORMAT_R8_SNORM,
+	VK_FORMAT_R8_UINT,
+	VK_FORMAT_R8_SINT,
+	VK_FORMAT_R8G8_UNORM,
+	VK_FORMAT_R8G8_SNORM,
+	VK_FORMAT_R8G8_UINT,
+	VK_FORMAT_R8G8_SINT,
+	VK_FORMAT_R8G8B8_UNORM,
+	VK_FORMAT_R8G8B8_SNORM,
+	VK_FORMAT_R8G8B8_UINT,
+	VK_FORMAT_R8G8B8_SINT,
+	VK_FORMAT_R8G8B8_SRGB,
+	VK_FORMAT_R8G8B8A8_UNORM,
+	VK_FORMAT_R8G8B8A8_SNORM,
+	VK_FORMAT_R8G8B8A8_UINT,
+	VK_FORMAT_R8G8B8A8_SINT,
+	VK_FORMAT_R8G8B8A8_SRGB,
+	VK_FORMAT_R16_UNORM,
+	VK_FORMAT_R16_SNORM,
+	VK_FORMAT_R16_UINT,
+	VK_FORMAT_R16_SINT,
+	VK_FORMAT_R16_SFLOAT,
+	VK_FORMAT_R16G16_UNORM,
+	VK_FORMAT_R16G16_SNORM,
+	VK_FORMAT_R16G16_UINT,
+	VK_FORMAT_R16G16_SINT,
+	VK_FORMAT_R16G16_SFLOAT,
+	VK_FORMAT_R16G16B16_UNORM,
+	VK_FORMAT_R16G16B16_SNORM,
+	VK_FORMAT_R16G16B16_UINT,
+	VK_FORMAT_R16G16B16_SINT,
+	VK_FORMAT_R16G16B16_SFLOAT,
+	VK_FORMAT_R16G16B16A16_UNORM,
+	VK_FORMAT_R16G16B16A16_SNORM,
+	VK_FORMAT_R16G16B16A16_UINT,
+	VK_FORMAT_R16G16B16A16_SINT,
+	VK_FORMAT_R16G16B16A16_SFLOAT,
+	VK_FORMAT_R32_UINT,
+	VK_FORMAT_R32_SINT,
+	VK_FORMAT_R32_SFLOAT,
+	VK_FORMAT_R32G32_UINT,
+	VK_FORMAT_R32G32_SINT,
+	VK_FORMAT_R32G32_SFLOAT,
+	VK_FORMAT_R32G32B32_UINT,
+	VK_FORMAT_R32G32B32_SINT,
+	VK_FORMAT_R32G32B32_SFLOAT,
+	VK_FORMAT_R32G32B32A32_UINT,
+	VK_FORMAT_R32G32B32A32_SINT,
+	VK_FORMAT_R32G32B32A32_SFLOAT
+};
+
+static const VkFormat s_depthStencilFormats[] =
+{
+	VK_FORMAT_D16_UNORM,
+	VK_FORMAT_D24_UNORM_X8,
+	VK_FORMAT_D32_SFLOAT,
+	VK_FORMAT_S8_UINT,
+	VK_FORMAT_D24_UNORM_S8_UINT
+};
+
+de::MovePtr<tcu::TestCaseGroup> createAttachmentTestCaseGroup (tcu::TestContext& testCtx)
+{
+	const deUint32 attachmentCounts[] = { 1, 3, 8 };
+	const VkAttachmentLoadOp loadOps[] =
+	{
+		VK_ATTACHMENT_LOAD_OP_LOAD,
+		VK_ATTACHMENT_LOAD_OP_CLEAR,
+		VK_ATTACHMENT_LOAD_OP_DONT_CARE
+	};
+
+	const VkAttachmentStoreOp storeOps[] =
+	{
+		VK_ATTACHMENT_STORE_OP_STORE,
+ 		VK_ATTACHMENT_STORE_OP_DONT_CARE
+	};
+
+	const VkImageLayout initialAndFinalLayouts[] =
+	{
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
+		VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL
+	};
+
+	const VkImageLayout subpassLayouts[] =
+	{
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+	};
+
+	const VkImageLayout depthStencilLayouts[] =
+	{
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+	};
+
+	const TestConfig::RenderTypes renderCommands[] =
+	{
+		TestConfig::RENDERTYPES_NONE,
+		TestConfig::RENDERTYPES_CLEAR,
+		TestConfig::RENDERTYPES_DRAW,
+		TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
+	};
+
+	const TestConfig::CommandBufferTypes commandBuffers[] =
+	{
+		TestConfig::COMMANDBUFFERTYPES_INLINE,
+		TestConfig::COMMANDBUFFERTYPES_SECONDARY,
+		TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
+	};
+
+	const TestConfig::ImageMemory imageMemories[] =
+	{
+		TestConfig::IMAGEMEMORY_STRICT,
+		TestConfig::IMAGEMEMORY_LAZY,
+		TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
+	};
+
+	const UVec2 targetSizes[] =
+	{
+		UVec2(64, 64),
+		UVec2(63, 65)
+	};
+
+	const UVec2 renderPositions[] =
+	{
+		UVec2(0, 0),
+		UVec2(3, 17)
+	};
+
+	const UVec2 renderSizes[] =
+	{
+		UVec2(32, 32),
+		UVec2(60, 47)
+	};
+
+	de::Random rng (1433774382u);
+	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "attachment", "Attachment format and count tests with load and store ops and image layouts"));
+
+	for (size_t attachmentCountNdx = 0; attachmentCountNdx < DE_LENGTH_OF_ARRAY(attachmentCounts); attachmentCountNdx++)
+	{
+		const deUint32					attachmentCount			= attachmentCounts[attachmentCountNdx];
+		const deUint32					testCaseCount			= (attachmentCount == 1 ? 100 : 200);
+		de::MovePtr<tcu::TestCaseGroup>	attachmentCountGroup	(new tcu::TestCaseGroup(testCtx, de::toString(attachmentCount).c_str(), de::toString(attachmentCount).c_str()));
+
+		for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
+		{
+			const bool					useDepthStencil		= rng.getBool();
+			VkImageLayout				depthStencilLayout	= VK_IMAGE_LAYOUT_GENERAL;
+			vector<Attachment>			attachments;
+			vector<AttachmentReference>	colorAttachmentReferences;
+
+			for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
+			{
+				const deUint32				sampleCount		= 1;
+				const VkFormat				format			= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_colorFormats), DE_ARRAY_END(s_colorFormats));
+				const VkAttachmentLoadOp	loadOp			= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	storeOp			= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				const VkImageLayout			initialLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+				const VkImageLayout			finalizeLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+				const VkImageLayout			subpassLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+				const VkAttachmentLoadOp	stencilLoadOp	= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	stencilStoreOp	= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
+				colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
+			}
+
+			if (useDepthStencil)
+			{
+				const deUint32				sampleCount			= 1;
+				const VkFormat				format				= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_depthStencilFormats), DE_ARRAY_END(s_depthStencilFormats));
+				const VkAttachmentLoadOp	loadOp				= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	storeOp				= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				const VkImageLayout			initialLayout		= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+				const VkImageLayout			finalizeLayout		= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+
+				const VkAttachmentLoadOp	stencilLoadOp		= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	stencilStoreOp		= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				depthStencilLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(depthStencilLayouts), DE_ARRAY_END(depthStencilLayouts));
+				attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
+			}
+
+			{
+				const TestConfig::RenderTypes			render			= rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
+				const TestConfig::CommandBufferTypes	commandBuffer	= rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
+				const TestConfig::ImageMemory			imageMemory		= rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
+				const vector<Subpass>					subpasses		(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference((useDepthStencil ? (deUint32)(attachments.size() - 1) : VK_ATTACHMENT_UNUSED), depthStencilLayout), vector<AttachmentReference>()));
+				const vector<SubpassDependency>			deps;
+
+				const string							testCaseName	= de::toString(attachmentCountNdx * testCaseCount + testCaseNdx);
+				const RenderPass						renderPass		(attachments, subpasses, deps);
+				const UVec2								targetSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
+				const UVec2								renderPos		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
+				const UVec2								renderSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
+
+				addFunctionCaseWithPrograms<TestConfig>(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 1293809));
+			}
+		}
+
+		group->addChild(attachmentCountGroup.release());
+	}
+
+	return group;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createAttachmentAllocationTestGroup (tcu::TestContext& testCtx)
+{
+	const deUint32 attachmentCounts[] = { 4, 8 };
+	const VkAttachmentLoadOp loadOps[] =
+	{
+		VK_ATTACHMENT_LOAD_OP_LOAD,
+		VK_ATTACHMENT_LOAD_OP_CLEAR,
+		VK_ATTACHMENT_LOAD_OP_DONT_CARE
+	};
+
+	const VkAttachmentStoreOp storeOps[] =
+	{
+		VK_ATTACHMENT_STORE_OP_STORE,
+		VK_ATTACHMENT_STORE_OP_DONT_CARE
+	};
+
+	const VkImageLayout initialAndFinalLayouts[] =
+	{
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
+		VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL
+	};
+
+	const VkImageLayout subpassLayouts[] =
+	{
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+	};
+
+	enum AllocationType
+	{
+		// Each pass uses one more attachmen than previous one
+		ALLOCATIONTYPE_GROW,
+		// Each pass uses one less attachment than previous one
+		ALLOCATIONTYPE_SHRINK,
+		// Each pass drops one attachment and picks up new one
+		ALLOCATIONTYPE_ROLL,
+		// Start by growing and end by shrinking
+		ALLOCATIONTYPE_GROW_SHRINK
+	};
+
+	const AllocationType allocationTypes[] =
+	{
+		ALLOCATIONTYPE_GROW,
+		ALLOCATIONTYPE_SHRINK,
+		ALLOCATIONTYPE_ROLL,
+		ALLOCATIONTYPE_GROW_SHRINK
+	};
+
+	const char* const allocationTypeStr[] =
+	{
+		"grow",
+		"shrink",
+		"roll",
+		"grow_shrink"
+	};
+
+	const TestConfig::RenderTypes renderCommands[] =
+	{
+		TestConfig::RENDERTYPES_NONE,
+		TestConfig::RENDERTYPES_CLEAR,
+		TestConfig::RENDERTYPES_DRAW,
+		TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW,
+	};
+
+	const TestConfig::CommandBufferTypes commandBuffers[] =
+	{
+		TestConfig::COMMANDBUFFERTYPES_INLINE,
+		TestConfig::COMMANDBUFFERTYPES_SECONDARY,
+		TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY
+	};
+
+	const TestConfig::ImageMemory imageMemories[] =
+	{
+		TestConfig::IMAGEMEMORY_STRICT,
+		TestConfig::IMAGEMEMORY_LAZY,
+		TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY
+	};
+
+	const UVec2 targetSizes[] =
+	{
+		UVec2(64, 64),
+		UVec2(63, 65)
+	};
+
+	const UVec2 renderPositions[] =
+	{
+		UVec2(0, 0),
+		UVec2(3, 17)
+	};
+
+	const UVec2 renderSizes[] =
+	{
+		UVec2(32, 32),
+		UVec2(60, 47)
+	};
+
+	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "attachment_allocation", "Attachment allocation tests"));
+	de::Random						rng		(3700649827u);
+
+	for (size_t allocationTypeNdx = 0; allocationTypeNdx < DE_LENGTH_OF_ARRAY(allocationTypes); allocationTypeNdx++)
+	{
+		const AllocationType			allocationType		= allocationTypes[allocationTypeNdx];
+		const size_t					testCaseCount		= 100;
+		de::MovePtr<tcu::TestCaseGroup>	allocationTypeGroup	(new tcu::TestCaseGroup(testCtx, allocationTypeStr[allocationTypeNdx], allocationTypeStr[allocationTypeNdx]));
+
+		for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++)
+		{
+			const deUint32		attachmentCount	= rng.choose<deUint32>(DE_ARRAY_BEGIN(attachmentCounts), DE_ARRAY_END(attachmentCounts));
+			vector<Attachment>	attachments;
+			vector<Subpass>		subpasses;
+
+			for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++)
+			{
+				const deUint32				sampleCount		= 1;
+				const VkFormat				format			= rng.choose<VkFormat>(DE_ARRAY_BEGIN(s_colorFormats), DE_ARRAY_END(s_colorFormats));
+				const VkAttachmentLoadOp	loadOp			= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	storeOp			= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				const VkImageLayout			initialLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+				const VkImageLayout			finalizeLayout	= rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(initialAndFinalLayouts), DE_ARRAY_END(initialAndFinalLayouts));
+
+				const VkAttachmentLoadOp	stencilLoadOp	= rng.choose<VkAttachmentLoadOp>(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps));
+				const VkAttachmentStoreOp	stencilStoreOp	= rng.choose<VkAttachmentStoreOp>(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps));
+
+				attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout));
+			}
+
+			if (allocationType == ALLOCATIONTYPE_GROW)
+			{
+				for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
+				{
+					vector<AttachmentReference>	colorAttachmentReferences;
+
+					for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
+					{
+						const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+						colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
+					}
+
+					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
+				}
+			}
+			else if (allocationType == ALLOCATIONTYPE_SHRINK)
+			{
+				for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
+				{
+					vector<AttachmentReference>	colorAttachmentReferences;
+
+					for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
+					{
+						const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+						colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
+					}
+
+					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
+				}
+			}
+			else if (allocationType == ALLOCATIONTYPE_ROLL)
+			{
+				for (size_t subpassNdx = 0; subpassNdx < attachmentCount / 2; subpassNdx++)
+				{
+					vector<AttachmentReference>	colorAttachmentReferences;
+
+					for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount / 2; attachmentNdx++)
+					{
+						const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+						colorAttachmentReferences.push_back(AttachmentReference((deUint32)(subpassNdx + attachmentNdx), subpassLayout));
+					}
+
+					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
+				}
+			}
+			else if (allocationType == ALLOCATIONTYPE_GROW_SHRINK)
+			{
+				for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
+				{
+					vector<AttachmentReference>	colorAttachmentReferences;
+
+					for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++)
+					{
+						const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+						colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
+					}
+
+					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
+				}
+
+				for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++)
+				{
+					vector<AttachmentReference>	colorAttachmentReferences;
+
+					for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++)
+					{
+						const VkImageLayout subpassLayout = rng.choose<VkImageLayout>(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts));
+
+						colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout));
+					}
+
+					subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<AttachmentReference>()));
+				}
+			}
+			else
+				DE_FATAL("Unknown allocation type");
+
+			{
+				const TestConfig::RenderTypes			render			= rng.choose<TestConfig::RenderTypes>(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands));
+				const TestConfig::CommandBufferTypes	commandBuffer	= rng.choose<TestConfig::CommandBufferTypes>(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers));
+				const TestConfig::ImageMemory			imageMemory		= rng.choose<TestConfig::ImageMemory>(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories));
+
+				const string							testCaseName	= de::toString(testCaseNdx);
+				const UVec2								targetSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes));
+				const UVec2								renderPos		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions));
+				const UVec2								renderSize		= rng.choose<UVec2>(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes));
+
+				vector<SubpassDependency>				deps;
+
+				for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++)
+				{
+					const bool byRegion				= rng.getBool();
+					deps.push_back(SubpassDependency((deUint32)subpassNdx, (deUint32)subpassNdx + 1,
+													 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+														| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+														| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+														| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+
+													 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+														| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+														| VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+														| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+
+													 VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,
+													 VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT,
+
+													 byRegion ? VK_TRUE : VK_FALSE));
+				}
+
+				const RenderPass					renderPass		(attachments, subpasses, deps);
+
+				addFunctionCaseWithPrograms<TestConfig>(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329));
+			}
+		}
+
+		group->addChild(allocationTypeGroup.release());
+	}
+
+	return group;
+}
+
+de::MovePtr<tcu::TestCaseGroup> createSimpleTestGroup (tcu::TestContext& testCtx)
+{
+	const UVec2						targetSize	(64, 64);
+	const UVec2						renderPos	(0, 0);
+	const UVec2						renderSize	(64, 64);
+	de::MovePtr<tcu::TestCaseGroup>	group		(new tcu::TestCaseGroup(testCtx, "simple", "Simple basic render pass tests"));
+
+	// color
+	{
+		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_R8G8B8A8_UNORM,
+																		  1,
+																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
+																		  VK_ATTACHMENT_STORE_OP_STORE,
+																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
+																		  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+																		  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "color", "Single color attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// depth
+	{
+		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_D24_UNORM_X8,
+																		  1,
+																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
+																		  VK_ATTACHMENT_STORE_OP_STORE,
+																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "depth", "Single depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// stencil
+	{
+		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_S8_UINT,
+																		  1,
+																		  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+																		  VK_ATTACHMENT_STORE_OP_DONT_CARE,
+																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
+																		  VK_ATTACHMENT_STORE_OP_STORE,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "stencil", "Single stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// depth_stencil
+	{
+		const RenderPass	renderPass	(vector<Attachment>(1, Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
+																		  1,
+																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
+																		  VK_ATTACHMENT_STORE_OP_STORE,
+																		  VK_ATTACHMENT_LOAD_OP_CLEAR,
+																		  VK_ATTACHMENT_STORE_OP_STORE,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+																		  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "depth_stencil", "Single depth stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// color_depth
+	{
+		const Attachment	attachments[] =
+		{
+			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
+			Attachment(VK_FORMAT_D24_UNORM_X8,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+		};
+
+		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_depth", "Color and depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// color_stencil
+	{
+		const Attachment	attachments[] =
+		{
+			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
+			Attachment(VK_FORMAT_S8_UINT,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+		};
+
+		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_stencil", "Color and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	// color_depth_stencil
+	{
+		const Attachment	attachments[] =
+		{
+			Attachment(VK_FORMAT_R8G8B8A8_UNORM,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+					   VK_ATTACHMENT_STORE_OP_DONT_CARE,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
+			Attachment(VK_FORMAT_D24_UNORM_S8_UINT,
+					   1,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_ATTACHMENT_LOAD_OP_CLEAR,
+					   VK_ATTACHMENT_STORE_OP_STORE,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+					   VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+		};
+
+		const RenderPass	renderPass	(vector<Attachment>(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)),
+										 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																	0u,
+																	vector<AttachmentReference>(),
+																	vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+																	vector<AttachmentReference>(),
+																	AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL),
+																	vector<AttachmentReference>())),
+										 vector<SubpassDependency>());
+
+		addFunctionCaseWithPrograms<TestConfig>(group.get(), "color_depth_stencil", "Color, depth and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+	}
+
+	return group;
+}
+
+std::string formatToName (VkFormat format)
+{
+	const std::string	formatStr	= de::toString(format);
+	const std::string	prefix		= "VK_FORMAT_";
+
+	DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix);
+
+	return de::toLower(formatStr.substr(prefix.length()));
+}
+
+de::MovePtr<tcu::TestCaseGroup> createFormatTestGroup(tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "formats", "Tests for different image formats."));
+
+	const UVec2 targetSize	(64, 64);
+	const UVec2 renderPos	(0, 0);
+	const UVec2 renderSize	(64, 64);
+
+	const struct
+	{
+		const char* const			str;
+		const VkAttachmentLoadOp	op;
+	} loadOps[] =
+	{
+		{ "clear",		VK_ATTACHMENT_LOAD_OP_CLEAR		},
+		{ "load",		VK_ATTACHMENT_LOAD_OP_LOAD		},
+		{ "dont_care",	VK_ATTACHMENT_LOAD_OP_DONT_CARE	}
+	};
+
+	const struct
+	{
+		 const char* const				str;
+		 const TestConfig::RenderTypes	types;
+	} renderTypes[] =
+	{
+		{ "clear",		TestConfig::RENDERTYPES_CLEAR								},
+		{ "draw",		TestConfig::RENDERTYPES_DRAW								},
+		{ "clear_draw",	TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW	}
+	};
+
+	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_colorFormats); formatNdx++)
+	{
+		const VkFormat					format		= s_colorFormats[formatNdx];
+		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatToName(format).c_str(), de::toString(format).c_str()));
+
+		for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++)
+		{
+			const VkAttachmentLoadOp		loadOp	= loadOps[loadOpNdx].op;
+			de::MovePtr<tcu::TestCaseGroup>	loadOpGroup	(new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str));
+
+			for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++)
+			{
+				const RenderPass	renderPass	(vector<Attachment>(1, Attachment(format,
+																				  1,
+																				  loadOp,
+																				  VK_ATTACHMENT_STORE_OP_STORE,
+																				  VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+																				  VK_ATTACHMENT_STORE_OP_DONT_CARE,
+																				  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+																				  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+												 vector<Subpass>(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS,
+																			0u,
+																			vector<AttachmentReference>(),
+																			vector<AttachmentReference>(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)),
+																			vector<AttachmentReference>(),
+																			AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL),
+																			vector<AttachmentReference>())),
+												 vector<SubpassDependency>());
+
+				addFunctionCaseWithPrograms<TestConfig>(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239));
+			}
+
+			formatGroup->addChild(loadOpGroup.release());
+		}
+
+		group->addChild(formatGroup.release());
+	}
+
+	return group;
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createRenderPassTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	renderpassTests	(new tcu::TestCaseGroup(testCtx, "renderpass", "RenderPass Tests"));
+
+	renderpassTests->addChild(createSimpleTestGroup(testCtx).release());
+	renderpassTests->addChild(createFormatTestGroup(testCtx).release());
+	renderpassTests->addChild(createAttachmentTestCaseGroup(testCtx).release());
+	renderpassTests->addChild(createAttachmentAllocationTestGroup(testCtx).release());
+
+	return renderpassTests.release();
+}
+
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/vktRenderPassTests.hpp b/external/vulkancts/modules/vulkan/vktRenderPassTests.hpp
new file mode 100644
index 0000000..9e6ec87
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktRenderPassTests.hpp
@@ -0,0 +1,47 @@
+#ifndef _VKTMULTIPASSTESTS_HPP
+#define _VKTMULTIPASSTESTS_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief RenderPass tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+
+tcu::TestCaseGroup*	createRenderPassTests	(tcu::TestContext& testCtx);
+
+} // vkt
+
+#endif // _VKTMULTIPASSTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/vktShaderLibrary.cpp b/external/vulkancts/modules/vulkan/vktShaderLibrary.cpp
new file mode 100644
index 0000000..ff08261
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktShaderLibrary.cpp
@@ -0,0 +1,1789 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief ShaderLibrary Vulkan implementation
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderLibrary.hpp"
+#include "vktTestCase.hpp"
+
+#include "vkPrograms.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "gluShaderLibrary.hpp"
+#include "gluShaderUtil.hpp"
+
+#include "tcuStringTemplate.hpp"
+#include "tcuTexture.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuVector.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "deStringUtil.hpp"
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+
+#include <sstream>
+#include <map>
+
+namespace vkt
+{
+
+using std::string;
+using std::vector;
+using std::map;
+using std::pair;
+using std::ostringstream;
+
+using de::MovePtr;
+using de::UniquePtr;
+
+using glu::ShaderType;
+using glu::ProgramSources;
+using glu::DataType;
+
+using glu::sl::ShaderCaseSpecification;
+using glu::sl::ProgramSpecializationParams;
+using glu::sl::RequiredExtension;
+using glu::sl::Value;
+using glu::sl::ValueBlock;
+
+using tcu::TestStatus;
+using tcu::StringTemplate;
+using tcu::Vec2;
+using tcu::ConstPixelBufferAccess;
+using tcu::TextureFormat;
+using tcu::TestLog;
+
+using vk::SourceCollections;
+using vk::Move;
+using vk::Unique;
+
+namespace
+{
+
+enum
+{
+	REFERENCE_UNIFORM_BINDING	= 0,
+	USER_UNIFORM_BINDING		= 1
+};
+
+string getShaderName (ShaderType shaderType, size_t progNdx)
+{
+	ostringstream str;
+	str << glu::getShaderTypeName(shaderType);
+	if (progNdx > 0)
+		str << "_" << progNdx;
+	return str.str();
+}
+
+void genUniformBlock (ostringstream& out, const string& blockName, const string& instanceName, int setNdx, int bindingNdx, const vector<Value>& uniforms)
+{
+	out << "layout(";
+
+	if (setNdx != 0)
+		out << "set = " << setNdx << ", ";
+
+	out << "binding = " << bindingNdx << ", std140) uniform " << blockName << "\n"
+		<< "{\n";
+
+	for (vector<Value>::const_iterator val = uniforms.begin(); val != uniforms.end(); ++val)
+		out << "\t" << glu::declare(val->type, val->name, 1) << ";\n";
+
+	out << "}";
+
+	if (!instanceName.empty())
+		out << " " << instanceName;
+
+	out << ";\n";
+}
+
+void declareReferenceBlock (ostringstream& out, const ValueBlock& valueBlock)
+{
+	if (!valueBlock.outputs.empty())
+		genUniformBlock(out, "Reference", "ref", 0, REFERENCE_UNIFORM_BINDING, valueBlock.outputs);
+}
+
+void declareUniforms (ostringstream& out, const ValueBlock& valueBlock)
+{
+	if (!valueBlock.uniforms.empty())
+		genUniformBlock(out, "Uniforms", "", 0, USER_UNIFORM_BINDING, valueBlock.uniforms);
+}
+
+DataType getTransportType (DataType valueType)
+{
+	if (isDataTypeBoolOrBVec(valueType))
+		return glu::getDataTypeIntVec(getDataTypeScalarSize(valueType));
+	else
+		return valueType;
+}
+
+int getNumTransportLocations (DataType valueType)
+{
+	return isDataTypeMatrix(valueType) ? getDataTypeMatrixNumColumns(valueType) : 1;
+}
+
+// This functions builds a matching vertex shader for a 'both' case, when
+// the fragment shader is being tested.
+// We need to build attributes and varyings for each 'input'.
+string genVertexShader (const ShaderCaseSpecification& spec)
+{
+	ostringstream	res;
+	int				curInputLoc		= 0;
+	int				curOutputLoc	= 0;
+
+	res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
+
+	// Declarations (position + attribute/varying for each input).
+	res << "precision highp float;\n";
+	res << "precision highp int;\n";
+	res << "\n";
+	res << "layout(location = 0) in highp vec4 dEQP_Position;\n";
+	curInputLoc += 1;
+
+	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
+	{
+		const Value&		val					= spec.values.inputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		res << "layout(location = " << curInputLoc << ") in " << transportTypeStr << " a_" << val.name << ";\n";
+		res << "layout(location = " << curOutputLoc << ") flat out " << transportTypeStr << " " << (transportType != valueType ? "v_" : "") << val.name << ";\n";
+
+		curInputLoc		+= numLocs;
+		curOutputLoc	+= numLocs;
+	}
+	res << "\n";
+
+	// Main function.
+	// - gl_Position = dEQP_Position;
+	// - for each input: write attribute directly to varying
+	res << "void main()\n";
+	res << "{\n";
+	res << "	gl_Position = dEQP_Position;\n";
+	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
+	{
+		const Value&	val		= spec.values.inputs[ndx];
+		const string&	name	= val.name;
+
+		res << "	" << (getTransportType(val.type.getBasicType()) != val.type.getBasicType() ? "v_" : "")
+			<< name << " = a_" << name << ";\n";
+	}
+
+	res << "}\n";
+	return res.str();
+}
+
+void genCompareOp (ostringstream& output, const char* dstVec4Var, const ValueBlock& valueBlock, const char* checkVarName)
+{
+	bool isFirstOutput = true;
+
+	for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++)
+	{
+		const Value&	val		= valueBlock.outputs[ndx];
+
+		// Check if we're only interested in one variable (then skip if not the right one).
+		if (checkVarName && val.name != checkVarName)
+			continue;
+
+		// Prefix.
+		if (isFirstOutput)
+		{
+			output << "bool RES = ";
+			isFirstOutput = false;
+		}
+		else
+			output << "RES = RES && ";
+
+		// Generate actual comparison.
+		if (getDataTypeScalarType(val.type.getBasicType()) == glu::TYPE_FLOAT)
+			output << "isOk(" << val.name << ", ref." << val.name << ", 0.05);\n";
+		else
+			output << "isOk(" << val.name << ", ref." << val.name << ");\n";
+	}
+
+	if (isFirstOutput)
+		output << dstVec4Var << " = vec4(1.0);\n";
+	else
+		output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
+}
+
+string genFragmentShader (const ShaderCaseSpecification& spec)
+{
+	ostringstream	shader;
+	ostringstream	setup;
+	int				curInLoc	= 0;
+
+	shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
+
+	shader << "precision highp float;\n";
+	shader << "precision highp int;\n";
+	shader << "\n";
+
+	shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+	shader << "\n";
+
+	genCompareFunctions(shader, spec.values, false);
+	shader << "\n";
+
+	// Declarations (varying, reference for each output).
+	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
+	{
+		const Value&		val					= spec.values.outputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const char*	const	valueTypeStr		= getDataTypeName(valueType);
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		shader << "layout(location = " << curInLoc << ") flat in " << transportTypeStr << " " << (valueType != transportType ? "v_" : "") << val.name << ";\n";
+
+		if (valueType != transportType)
+			setup << "	" << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(v_" << val.name << ");\n";
+
+		curInLoc += numLocs;
+	}
+
+	declareReferenceBlock(shader, spec.values);
+
+	shader << "\n";
+	shader << "void main()\n";
+	shader << "{\n";
+
+	shader << setup.str();
+
+	shader << "	";
+	genCompareOp(shader, "dEQP_FragColor", spec.values, DE_NULL);
+
+	shader << "}\n";
+	return shader.str();
+}
+
+// Specialize a shader for the vertex shader test case.
+string specializeVertexShader (const ShaderCaseSpecification& spec, const string& src)
+{
+	ostringstream		decl;
+	ostringstream		setup;
+	ostringstream		output;
+	int					curInputLoc		= 0;
+	int					curOutputLoc	= 0;
+
+	// generated from "both" case
+	DE_ASSERT(spec.caseType == glu::sl::CASETYPE_VERTEX_ONLY);
+
+	// Output (write out position).
+	output << "gl_Position = dEQP_Position;\n";
+
+	// Declarations (position + attribute for each input, varying for each output).
+	decl << "layout(location = 0) in highp vec4 dEQP_Position;\n";
+	curInputLoc += 1;
+
+	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
+	{
+		const Value&		val					= spec.values.inputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const char*	const	valueTypeStr		= getDataTypeName(valueType);
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		decl << "layout(location = " << curInputLoc << ") in ";
+
+		curInputLoc += numLocs;
+
+		if (valueType == transportType)
+			decl << transportTypeStr << " " << val.name << ";\n";
+		else
+		{
+			decl << transportTypeStr << " a_" << val.name << ";\n";
+			setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(a_" << val.name << ");\n";
+		}
+	}
+
+	declareUniforms(decl, spec.values);
+
+	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
+	{
+		const Value&		val					= spec.values.outputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const char*	const	valueTypeStr		= getDataTypeName(valueType);
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		decl << "layout(location = " << curOutputLoc << ") flat out ";
+
+		curOutputLoc += numLocs;
+
+		if (valueType == transportType)
+			decl << transportTypeStr << " " << val.name << ";\n";
+		else
+		{
+			decl << transportTypeStr << " v_" << val.name << ";\n";
+			decl << valueTypeStr << " " << val.name << ";\n";
+
+			output << "v_" << val.name << " = " << transportTypeStr << "(" << val.name << ");\n";
+		}
+	}
+
+	// Shader specialization.
+	map<string, string> params;
+	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
+	params.insert(pair<string, string>("SETUP", setup.str()));
+	params.insert(pair<string, string>("OUTPUT", output.str()));
+	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
+
+	StringTemplate	tmpl	(src);
+	const string	baseSrc	= tmpl.specialize(params);
+	const string	withExt	= injectExtensionRequirements(baseSrc, spec.programs[0].requiredExtensions, glu::SHADERTYPE_VERTEX);
+
+	return withExt;
+}
+
+// Specialize a shader for the fragment shader test case.
+string specializeFragmentShader (const ShaderCaseSpecification& spec, const string& src)
+{
+	ostringstream		decl;
+	ostringstream		setup;
+	ostringstream		output;
+	int					curInputLoc	= 0;
+
+	// generated from "both" case
+	DE_ASSERT(spec.caseType == glu::sl::CASETYPE_FRAGMENT_ONLY);
+
+	genCompareFunctions(decl, spec.values, false);
+	genCompareOp(output, "dEQP_FragColor", spec.values, DE_NULL);
+
+	decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+
+	for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
+	{
+		const Value&		val					= spec.values.inputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const char*	const	valueTypeStr		= getDataTypeName(valueType);
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		decl << "layout(location = " << curInputLoc << ") flat in ";
+
+		curInputLoc += numLocs;
+
+		if (valueType == transportType)
+			decl << transportTypeStr << " " << val.name << ";\n";
+		else
+		{
+			decl << transportTypeStr << " v_" << val.name << ";\n";
+			setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(v_" << val.name << ");\n";
+		}
+	}
+
+	declareUniforms(decl, spec.values);
+	declareReferenceBlock(decl, spec.values);
+
+	for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
+	{
+		const Value&		val				= spec.values.outputs[ndx];
+		const DataType		basicType		= val.type.getBasicType();
+		const char* const	refTypeStr		= getDataTypeName(basicType);
+
+		decl << refTypeStr << " " << val.name << ";\n";
+	}
+
+	// Shader specialization.
+	map<string, string> params;
+	params.insert(pair<string, string>("DECLARATIONS", decl.str()));
+	params.insert(pair<string, string>("SETUP", setup.str()));
+	params.insert(pair<string, string>("OUTPUT", output.str()));
+	params.insert(pair<string, string>("POSITION_FRAG_COLOR", "dEQP_FragColor"));
+
+	StringTemplate	tmpl	(src);
+	const string	baseSrc	= tmpl.specialize(params);
+	const string	withExt	= injectExtensionRequirements(baseSrc, spec.programs[0].requiredExtensions, glu::SHADERTYPE_FRAGMENT);
+
+	return withExt;
+}
+
+map<string, string> generateVertexSpecialization (const ProgramSpecializationParams& specParams)
+{
+	ostringstream			decl;
+	ostringstream			setup;
+	map<string, string>		params;
+	int						curInputLoc		= 0;
+
+	decl << "layout(location = 0) in highp vec4 dEQP_Position;\n";
+	curInputLoc += 1;
+
+	for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++)
+	{
+		const Value&		val					= specParams.caseSpec.values.inputs[ndx];
+		const DataType		valueType			= val.type.getBasicType();
+		const char*	const	valueTypeStr		= getDataTypeName(valueType);
+		const DataType		transportType		= getTransportType(valueType);
+		const char* const	transportTypeStr	= getDataTypeName(transportType);
+		const int			numLocs				= getNumTransportLocations(valueType);
+
+		decl << "layout(location = " << curInputLoc << ") in ";
+
+		curInputLoc += numLocs;
+
+		if (valueType == transportType)
+			decl << transportTypeStr << " " << val.name << ";\n";
+		else
+		{
+			decl << transportTypeStr << " a_" << val.name << ";\n";
+			setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(a_" << val.name << ");\n";
+		}
+	}
+
+	declareUniforms(decl, specParams.caseSpec.values);
+
+	params.insert(pair<string, string>("VERTEX_DECLARATIONS",	decl.str()));
+	params.insert(pair<string, string>("VERTEX_SETUP",			setup.str()));
+	params.insert(pair<string, string>("VERTEX_OUTPUT",			string("gl_Position = dEQP_Position;\n")));
+
+	return params;
+}
+
+map<string, string> generateFragmentSpecialization (const ProgramSpecializationParams& specParams)
+{
+	ostringstream		decl;
+	ostringstream		output;
+	map<string, string>	params;
+
+	genCompareFunctions(decl, specParams.caseSpec.values, false);
+	genCompareOp(output, "dEQP_FragColor", specParams.caseSpec.values, DE_NULL);
+
+	decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
+
+	for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++)
+	{
+		const Value&		val			= specParams.caseSpec.values.outputs[ndx];
+		const char*	const	refTypeStr	= getDataTypeName(val.type.getBasicType());
+
+		decl << refTypeStr << " " << val.name << ";\n";
+	}
+
+	declareReferenceBlock(decl, specParams.caseSpec.values);
+	declareUniforms(decl, specParams.caseSpec.values);
+
+	params.insert(pair<string, string>("FRAGMENT_DECLARATIONS",	decl.str()));
+	params.insert(pair<string, string>("FRAGMENT_OUTPUT",		output.str()));
+	params.insert(pair<string, string>("FRAG_COLOR",			"dEQP_FragColor"));
+
+	return params;
+}
+
+map<string, string> generateGeometrySpecialization (const ProgramSpecializationParams& specParams)
+{
+	ostringstream		decl;
+	map<string, string>	params;
+
+	decl << "layout (triangles) in;\n";
+	decl << "layout (triangle_strip, max_vertices=3) out;\n";
+	decl << "\n";
+
+	declareUniforms(decl, specParams.caseSpec.values);
+
+	params.insert(pair<string, string>("GEOMETRY_DECLARATIONS",		decl.str()));
+
+	return params;
+}
+
+map<string, string> generateTessControlSpecialization (const ProgramSpecializationParams& specParams)
+{
+	ostringstream		decl;
+	ostringstream		output;
+	map<string, string>	params;
+
+	decl << "layout (vertices=3) out;\n";
+	decl << "\n";
+
+	declareUniforms(decl, specParams.caseSpec.values);
+
+	output <<	"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+				"gl_TessLevelInner[0] = 2.0;\n"
+				"gl_TessLevelInner[1] = 2.0;\n"
+				"gl_TessLevelOuter[0] = 2.0;\n"
+				"gl_TessLevelOuter[1] = 2.0;\n"
+				"gl_TessLevelOuter[2] = 2.0;\n"
+				"gl_TessLevelOuter[3] = 2.0;";
+
+	params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS",	decl.str()));
+	params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT",		output.str()));
+	params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",				de::toString(specParams.maxPatchVertices)));
+
+	return params;
+}
+
+map<string, string> generateTessEvalSpecialization (const ProgramSpecializationParams& specParams)
+{
+	ostringstream		decl;
+	ostringstream		output;
+	map<string, string>	params;
+
+	decl << "layout (triangles) in;\n";
+	decl << "\n";
+
+	declareUniforms(decl, specParams.caseSpec.values);
+
+	output <<	"gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + gl_TessCoord[2] * gl_in[2].gl_Position;\n";
+
+	params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS",	decl.str()));
+	params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT",		output.str()));
+	params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES",					de::toString(specParams.maxPatchVertices)));
+
+	return params;
+}
+
+void specializeShaderSources (ProgramSources&						dst,
+							  const ProgramSources&					src,
+							  const ProgramSpecializationParams&	specParams,
+							  glu::ShaderType						shaderType,
+							  map<string, string>					(*specializationGenerator) (const ProgramSpecializationParams& specParams))
+{
+	if (!src.sources[shaderType].empty())
+	{
+		const map<string, string>	tmplParams	= specializationGenerator(specParams);
+
+		for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx)
+		{
+			const StringTemplate	tmpl			(src.sources[shaderType][ndx]);
+			const string			baseGLSLCode	= tmpl.specialize(tmplParams);
+			const string			sourceWithExts	= injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType);
+
+			dst << glu::ShaderSource(shaderType, sourceWithExts);
+		}
+	}
+}
+
+void specializeProgramSources (glu::ProgramSources&					dst,
+							   const glu::ProgramSources&			src,
+							   const ProgramSpecializationParams&	specParams)
+{
+	specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_VERTEX,					generateVertexSpecialization);
+	specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_FRAGMENT,					generateFragmentSpecialization);
+	specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_GEOMETRY,					generateGeometrySpecialization);
+	specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_TESSELLATION_CONTROL,		generateTessControlSpecialization);
+	specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_TESSELLATION_EVALUATION,	generateTessEvalSpecialization);
+
+	dst << glu::ProgramSeparable(src.separable);
+}
+
+struct ValueBufferLayout
+{
+	struct Entry
+	{
+		int		offset;
+		int		vecStride;	//! Applies to matrices only
+
+		Entry (void) : offset(0), vecStride(0) {}
+		Entry (int offset_, int vecStride_) : offset(offset_), vecStride(vecStride_) {}
+	};
+
+	vector<Entry>	entries;
+	int				size;
+
+	ValueBufferLayout (void) : size(0) {}
+};
+
+ValueBufferLayout computeStd140Layout (const vector<Value>& values)
+{
+	ValueBufferLayout layout;
+
+	layout.entries.resize(values.size());
+
+	for (size_t ndx = 0; ndx < values.size(); ++ndx)
+	{
+		const DataType	basicType	= values[ndx].type.getBasicType();
+		const bool		isMatrix	= isDataTypeMatrix(basicType);
+		const int		numVecs		= isMatrix ? getDataTypeMatrixNumColumns(basicType) : 1;
+		const DataType	vecType		= isMatrix ? glu::getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType)) : basicType;
+		const int		vecSize		= getDataTypeScalarSize(vecType);
+		const int		alignment	= ((isMatrix || vecSize == 3) ? 4 : vecSize)*int(sizeof(deUint32));
+
+		layout.size			= deAlign32(layout.size, alignment);
+		layout.entries[ndx] = ValueBufferLayout::Entry(layout.size, alignment);
+		layout.size			+= alignment*(numVecs-1) + vecSize*int(sizeof(deUint32));
+	}
+
+	return layout;
+}
+
+ValueBufferLayout computeStd430Layout (const vector<Value>& values)
+{
+	ValueBufferLayout layout;
+
+	layout.entries.resize(values.size());
+
+	for (size_t ndx = 0; ndx < values.size(); ++ndx)
+	{
+		const DataType	basicType	= values[ndx].type.getBasicType();
+		const int		numVecs		= isDataTypeMatrix(basicType) ? getDataTypeMatrixNumColumns(basicType) : 1;
+		const DataType	vecType		= isDataTypeMatrix(basicType) ? glu::getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType)) : basicType;
+		const int		vecSize		= getDataTypeScalarSize(vecType);
+		const int		alignment	= (vecSize == 3 ? 4 : vecSize)*int(sizeof(deUint32));
+
+		layout.size			= deAlign32(layout.size, alignment);
+		layout.entries[ndx] = ValueBufferLayout::Entry(layout.size, alignment);
+		layout.size			+= alignment*(numVecs-1) + vecSize*int(sizeof(deUint32));
+	}
+
+	return layout;
+}
+
+void copyToLayout (void* dst, const ValueBufferLayout::Entry& entryLayout, const Value& value, int arrayNdx)
+{
+	const DataType	basicType	= value.type.getBasicType();
+	const int		scalarSize	= getDataTypeScalarSize(basicType);
+	const int		numVecs		= isDataTypeMatrix(basicType) ? getDataTypeMatrixNumColumns(basicType) : 1;
+	const int		numComps	= isDataTypeMatrix(basicType) ? getDataTypeMatrixNumRows(basicType) : scalarSize;
+
+	DE_ASSERT(size_t((arrayNdx+1)*scalarSize) <= value.elements.size());
+
+	for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
+		deMemcpy((deUint8*)dst + entryLayout.offset + vecNdx*entryLayout.vecStride,
+				 &value.elements[arrayNdx*scalarSize + vecNdx*numComps],
+				 numComps*sizeof(deUint32));
+}
+
+void copyToLayout (void* dst, const ValueBufferLayout& layout, const vector<Value>& values, int arrayNdx)
+{
+	DE_ASSERT(layout.entries.size() == values.size());
+
+	for (size_t ndx = 0; ndx < values.size(); ndx++)
+		copyToLayout(dst, layout.entries[ndx], values[ndx], arrayNdx);
+}
+
+Move<vk::VkShader> createShader (Context& context, vk::VkShaderModule module, vk::VkShaderStage stage, const char* name)
+{
+	const vk::VkShaderCreateInfo	params	=
+	{
+		vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,	// sType
+		DE_NULL,									// pNext
+		module,										// module
+		name,										// pName
+		0u,											// flags
+		stage,										// stage
+	};
+
+	return vk::createShader(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+deUint32 getShaderStages (const ShaderCaseSpecification& spec)
+{
+	if (spec.caseType == glu::sl::CASETYPE_COMPLETE)
+	{
+		deUint32	stages	= 0u;
+
+		for (size_t progNdx = 0; progNdx < spec.programs.size(); progNdx++)
+		{
+			for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+			{
+				if (!spec.programs[progNdx].sources.sources[shaderType].empty())
+					stages |= (1u << shaderType);
+			}
+		}
+
+		return stages;
+	}
+	else
+		return (1u << glu::SHADERTYPE_VERTEX) | (1u << glu::SHADERTYPE_FRAGMENT);
+}
+
+class PipelineProgram
+{
+public:
+								PipelineProgram		(Context& context, const ShaderCaseSpecification& spec);
+
+	deUint32					getStages			(void) const					{ return m_stages;							}
+
+	bool						hasShader			(glu::ShaderType type) const	{ return (m_stages & (1u << type)) != 0;	}
+	vk::VkShader				getShader			(glu::ShaderType type) const	{ return *m_shaders[type];					}
+
+private:
+	const deUint32				m_stages;
+	Move<vk::VkShaderModule>	m_shaderModules[glu::SHADERTYPE_LAST];
+	Move<vk::VkShader>			m_shaders[glu::SHADERTYPE_LAST];
+};
+
+PipelineProgram::PipelineProgram (Context& context, const ShaderCaseSpecification& spec)
+	: m_stages(getShaderStages(spec))
+{
+	// \note Currently only a single source program is supported as framework lacks SPIR-V linking capability
+	TCU_CHECK_INTERNAL(spec.programs.size() == 1);
+
+	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+	{
+		if ((m_stages & (1u << shaderType)) != 0)
+		{
+			m_shaderModules[shaderType]	= vk::createShaderModule(context.getDeviceInterface(), context.getDevice(),
+																 context.getBinaryCollection().get(getShaderName((glu::ShaderType)shaderType, 0)), 0u);
+			m_shaders[shaderType]		= createShader(context, *m_shaderModules[shaderType], vk::getVkShaderStage((glu::ShaderType)shaderType), "main");
+		}
+	}
+}
+
+vector<vk::VkPipelineShaderStageCreateInfo> getPipelineShaderStageCreateInfo (const PipelineProgram& program)
+{
+	vector<vk::VkPipelineShaderStageCreateInfo>	infos;
+
+	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+	{
+		if (program.hasShader((glu::ShaderType)shaderType))
+		{
+			const vk::VkPipelineShaderStageCreateInfo info =
+			{
+				vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// sType
+				DE_NULL,													// pNext
+				vk::getVkShaderStage((glu::ShaderType)shaderType),			// stage
+				program.getShader((glu::ShaderType)shaderType),				// shader
+				DE_NULL,													// pSpecializationInfo
+			};
+
+			infos.push_back(info);
+		}
+	}
+
+	return infos;
+}
+
+Move<vk::VkBuffer> createBuffer (Context& context, vk::VkDeviceSize size, vk::VkBufferUsageFlags usageFlags)
+{
+	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+	const vk::VkBufferCreateInfo	params				=
+	{
+		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// sType
+		DE_NULL,									// pNext
+		size,										// size
+		usageFlags,									// usage
+		0u,											// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
+		1u,											// queueFamilyCount
+		&queueFamilyIndex,							// pQueueFamilyIndices
+	};
+
+	return vk::createBuffer(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkImage> createImage2D (Context& context, int width, int height, vk::VkFormat format, vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
+{
+	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+	const vk::VkImageCreateInfo		params				=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// sType
+		DE_NULL,									// pNext
+		vk::VK_IMAGE_TYPE_2D,						// imageType
+		format,										// format
+		{ width, height, 1 },						// extent
+		1u,											// mipLevels
+		1u,											// arraySize
+		1u,											// samples
+		tiling,										// tiling
+		usageFlags,									// usage
+		0u,											// flags
+		vk::VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
+		1u,											// queueFamilyCount
+		&queueFamilyIndex,							// pQueueFamilyIndices
+		vk::VK_IMAGE_LAYOUT_UNDEFINED,				// initialLayout
+	};
+
+	return vk::createImage(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkImageView> createAttachmentView (Context& context, vk::VkImage image, vk::VkFormat format)
+{
+	const vk::VkImageViewCreateInfo	params				=
+	{
+		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// sType
+		DE_NULL,											// pNext
+		image,												// image
+		vk::VK_IMAGE_VIEW_TYPE_2D,							// viewType
+		format,												// format
+		vk::makeChannelMappingRGBA(),						// channels
+		{
+			vk::VK_IMAGE_ASPECT_COLOR_BIT,						// aspectMask
+			0u,													// baseMipLevel
+			1u,													// mipLevels
+			0u,													// baseArrayLayer
+			1u,													// arraySize
+		},													// subresourceRange
+		0u,													// flags
+	};
+
+	return vk::createImageView(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkRenderPass> createRenderPass (Context& context, vk::VkFormat colorAttFormat)
+{
+	const vk::VkAttachmentDescription	colorAttDesc		=
+	{
+		vk::VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,			// sType;
+		DE_NULL,												// pNext;
+		colorAttFormat,											// format;
+		1u,														// samples;
+		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						// loadOp;
+		vk::VK_ATTACHMENT_STORE_OP_STORE,						// storeOp;
+		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// stencilLoadOp;
+		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,					// stencilStoreOp;
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// initialLayout;
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// finalLayout;
+		0u,														// flags;
+	};
+	const vk::VkAttachmentReference		colorAttRef			=
+	{
+		0u,														// attachment;
+		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// layout;
+	};
+	const vk::VkSubpassDescription		subpassDesc			=
+	{
+		vk::VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,				// sType;
+		DE_NULL,												// pNext;
+		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,					// pipelineBindPoint;
+		0u,														// flags;
+		0u,														// inputCount;
+		DE_NULL,												// pInputAttachments;
+		1u,														// colorCount;
+		&colorAttRef,											// pColorAttachments;
+		DE_NULL,												// pResolveAttachments;
+		{ vk::VK_NO_ATTACHMENT, vk::VK_IMAGE_LAYOUT_GENERAL },	// depthStencilAttachment;
+		0u,														// preserveCount;
+		DE_NULL,												// pPreserveAttachments;
+
+	};
+	const vk::VkRenderPassCreateInfo	renderPassParams	=
+	{
+		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// sType;
+		DE_NULL,												// pNext;
+		1u,														// attachmentCount;
+		&colorAttDesc,											// pAttachments;
+		1u,														// subpassCount;
+		&subpassDesc,											// pSubpasses;
+		0u,														// dependencyCount;
+		DE_NULL,												// pDependencies;
+	};
+
+	return vk::createRenderPass(context.getDeviceInterface(), context.getDevice(), &renderPassParams);
+}
+
+vk::VkShaderStageFlags getVkStageFlags (deUint32 stages)
+{
+	vk::VkShaderStageFlags	vkStages	= 0u;
+
+	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+	{
+		if ((stages & (1u << shaderType)) != 0)
+			vkStages |= 1u << vk::getVkShaderStage((glu::ShaderType)shaderType);
+	}
+
+	return vkStages;
+}
+
+Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (Context& context, deUint32 shaderStages)
+{
+	DE_STATIC_ASSERT(REFERENCE_UNIFORM_BINDING	== 0);
+	DE_STATIC_ASSERT(USER_UNIFORM_BINDING		== 1);
+
+	return vk::DescriptorSetLayoutBuilder()
+				.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT)
+				.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, getVkStageFlags(shaderStages))
+				.build(context.getDeviceInterface(), context.getDevice());
+}
+
+Move<vk::VkPipelineLayout> createPipelineLayout (Context& context, vk::VkDescriptorSetLayout descriptorSetLayout)
+{
+	const vk::VkPipelineLayoutCreateInfo	params	=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// sType
+		DE_NULL,											// pNext
+		1u,													// descriptorSetCount
+		&descriptorSetLayout,								// pSetLayouts
+		0u,													// pushConstantRangeCount
+		DE_NULL,											// pPushConstantRanges
+	};
+
+	return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+vk::VkFormat getFloatVecFormat (int scalarSize)
+{
+	const vk::VkFormat vecFmts[] =
+	{
+		vk::VK_FORMAT_R32_SFLOAT,
+		vk::VK_FORMAT_R32G32_SFLOAT,
+		vk::VK_FORMAT_R32G32B32_SFLOAT,
+		vk::VK_FORMAT_R32G32B32A32_SFLOAT,
+	};
+	return de::getSizedArrayElement<4>(vecFmts, scalarSize-1);
+}
+
+vector<vk::VkVertexInputAttributeDescription> getVertexAttributeDescriptions (const vector<Value>& inputValues, const ValueBufferLayout& layout)
+{
+	vector<vk::VkVertexInputAttributeDescription>	attribs;
+
+	// Position
+	{
+		const vk::VkVertexInputAttributeDescription	posDesc	=
+		{
+			0u,								// location
+			0u,								// binding
+			vk::VK_FORMAT_R32G32_SFLOAT,	// format
+			0u,								// offsetInBytes
+		};
+
+		attribs.push_back(posDesc);
+	}
+
+	// Input values
+	for (size_t inputNdx = 0; inputNdx < inputValues.size(); inputNdx++)
+	{
+		const Value&					input		= inputValues[inputNdx];
+		const ValueBufferLayout::Entry&	layoutEntry	= layout.entries[inputNdx];
+		const DataType					basicType	= input.type.getBasicType();
+		const int						numVecs		= isDataTypeMatrix(basicType)
+													? getDataTypeMatrixNumRows(basicType)
+													: 1;
+		const int						vecSize		= isDataTypeMatrix(basicType)
+													? getDataTypeMatrixNumColumns(basicType)
+													: getDataTypeScalarSize(basicType);
+		const vk::VkFormat				vecFmt		= getFloatVecFormat(vecSize);
+
+		for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
+		{
+			const deUint32								curLoc	= (deUint32)attribs.size();
+			const deUint32								offset	= (deUint32)(layoutEntry.offset + layoutEntry.vecStride*vecNdx);
+			const vk::VkVertexInputAttributeDescription	desc	=
+			{
+				curLoc,		// location
+				1u,			// binding
+				vecFmt,		// format
+				offset,		// offsetInBytes
+			};
+
+			attribs.push_back(desc);
+		}
+	}
+
+	return attribs;
+}
+
+Move<vk::VkPipeline> createPipeline (Context&					context,
+									 const vector<Value>&		inputValues,
+									 const ValueBufferLayout&	inputLayout,
+									 const PipelineProgram&		program,
+									 vk::VkRenderPass			renderPass,
+									 vk::VkPipelineLayout		pipelineLayout,
+									 tcu::IVec2					renderSize)
+{
+	const vector<vk::VkPipelineShaderStageCreateInfo>	shaderStageParams		(getPipelineShaderStageCreateInfo(program));
+	const vector<vk::VkVertexInputAttributeDescription>	vertexAttribParams		(getVertexAttributeDescriptions(inputValues, inputLayout));
+	const vk::VkPipelineDepthStencilStateCreateInfo		depthStencilParams		=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// sType;
+		DE_NULL,															// pNext;
+		vk::VK_FALSE,														// depthTestEnable;
+		vk::VK_FALSE,														// depthWriteEnable;
+		vk::VK_COMPARE_OP_ALWAYS,											// depthCompareOp;
+		vk::VK_FALSE,														// depthBoundsTestEnable;
+		vk::VK_FALSE,														// stencilTestEnable;
+		{
+			vk::VK_STENCIL_OP_KEEP,												// stencilFailOp;
+			vk::VK_STENCIL_OP_KEEP,												// stencilPassOp;
+			vk::VK_STENCIL_OP_KEEP,												// stencilDepthFailOp;
+			vk::VK_COMPARE_OP_ALWAYS,											// stencilCompareOp;
+			0u,																	// stencilCompareMask
+			0u,																	// stencilWriteMask
+			0u,																	// stencilReference
+		},																	// front;
+		{
+			vk::VK_STENCIL_OP_KEEP,												// stencilFailOp;
+			vk::VK_STENCIL_OP_KEEP,												// stencilPassOp;
+			vk::VK_STENCIL_OP_KEEP,												// stencilDepthFailOp;
+			vk::VK_COMPARE_OP_ALWAYS,											// stencilCompareOp;
+			0u,																	// stencilCompareMask
+			0u,																	// stencilWriteMask
+			0u,																	// stencilReference
+		},																	// back;
+		-1.0f,																// minDepthBounds
+		+1.0f,																// maxDepthBounds
+	};
+	const vk::VkViewport								viewport0				=
+	{
+		0.0f,																// originX;
+		0.0f,																// originY;
+		(float)renderSize.x(),												// width;
+		(float)renderSize.y(),												// height;
+		0.0f,																// minDepth;
+		1.0f,																// maxDepth;
+	};
+	const vk::VkRect2D									scissor0				=
+	{
+		{ 0u, 0u },															// offset;
+		{ renderSize.x(), renderSize.y() }									// extent;
+	};
+	const vk::VkPipelineViewportStateCreateInfo			viewportParams			=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// sType;
+		DE_NULL,															// pNext;
+		1u,																	// viewportCount;
+		&viewport0,															// pViewports;
+		1u,																	// scissorCount;
+		&scissor0,															// pScissors
+	};
+	const vk::VkPipelineMultisampleStateCreateInfo		multisampleParams		=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// sType;
+		DE_NULL,															// pNext;
+		1u,																	// rasterSamples;
+		DE_FALSE,															// sampleShadingEnable;
+		0.0f,																// minSampleShading;
+		DE_NULL,															// pSampleMask;
+	};
+	const vk::VkPipelineRasterStateCreateInfo			rasterParams			=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,			// sType;
+		DE_NULL,															// pNext;
+		DE_TRUE,															// depthClipEnable;
+		DE_FALSE,															// rasterizerDiscardEnable;
+		vk::VK_FILL_MODE_SOLID,												// fillMode;
+		vk::VK_CULL_MODE_NONE,												// cullMode;
+		vk::VK_FRONT_FACE_CCW,												// frontFace;
+		vk::VK_FALSE,														// depthBiasEnable
+		0.0f,																// depthBias
+		0.0f,																// depthBiasClamp
+		0.0f,																// slopeScaledDepthBias
+		1.0f,																// lineWidth
+	};
+	const vk::VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams		=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// sType;
+		DE_NULL,															// pNext;
+		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// topology;
+		DE_FALSE,															// primitiveRestartEnable;
+	};
+	const vk::VkVertexInputBindingDescription			vertexBindings[]		=
+	{
+		{
+			0u,																	// binding;
+			(deUint32)sizeof(tcu::Vec2),										// strideInBytes;
+			vk::VK_VERTEX_INPUT_STEP_RATE_VERTEX,								// stepRate;
+		},
+		{
+			1u,																	// binding;
+			0u,																	// strideInBytes;
+			vk::VK_VERTEX_INPUT_STEP_RATE_INSTANCE,								// stepRate;
+		},
+	};
+	const vk::VkPipelineVertexInputStateCreateInfo		vertexInputStateParams	=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// sType;
+		DE_NULL,															// pNext;
+		DE_LENGTH_OF_ARRAY(vertexBindings),									// bindingCount;
+		vertexBindings,														// pVertexBindingDescriptions;
+		(deUint32)vertexAttribParams.size(),								// attributeCount;
+		&vertexAttribParams[0],												// pVertexAttributeDescriptions;
+	};
+	const vk::VkChannelFlags							allChnMask				= vk::VK_CHANNEL_R_BIT|vk::VK_CHANNEL_G_BIT|vk::VK_CHANNEL_B_BIT|vk::VK_CHANNEL_A_BIT;
+	const vk::VkPipelineColorBlendAttachmentState		attBlendParams			=
+	{
+		vk::VK_FALSE,														// blendEnable;
+		vk::VK_BLEND_ONE,													// srcBlendColor;
+		vk::VK_BLEND_ZERO,													// destBlendColor;
+		vk::VK_BLEND_OP_ADD,												// blendOpColor;
+		vk::VK_BLEND_ONE,													// srcBlendAlpha;
+		vk::VK_BLEND_ZERO,													// destBlendAlpha;
+		vk::VK_BLEND_OP_ADD,												// blendOpAlpha;
+		allChnMask,															// channelWriteMask;
+	};
+	const vk::VkPipelineColorBlendStateCreateInfo		blendParams				=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// sType;
+		DE_NULL,															// pNext;
+		vk::VK_FALSE,														// alphaToCoverageEnable;
+		vk::VK_FALSE,														// alphaToOneEnable;
+		vk::VK_FALSE,														// logicOpEnable;
+		vk::VK_LOGIC_OP_COPY,												// logicOp;
+		1u,																	// attachmentCount;
+		&attBlendParams,													// pAttachments;
+		{ 0.0f, 0.0f, 0.0f, 0.0f },											// blendConst
+	};
+	const vk::VkPipelineDynamicStateCreateInfo			dynStateParams			=
+	{
+		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,			// sType
+		DE_NULL,															// pNext
+		0u,																	// dynamicStateCount
+		DE_NULL,															// pDynamicStates
+	};
+	const vk::VkGraphicsPipelineCreateInfo				pipelineParams			=
+	{
+		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,				// sType;
+		DE_NULL,															// pNext;
+		(deUint32)shaderStageParams.size(),									// stageCount;
+		&shaderStageParams[0],												// pStages;
+		&vertexInputStateParams,											// pVertexInputState;
+		&inputAssemblyParams,												// pInputAssemblyState;
+		DE_NULL,															// pTessellationState;
+		&viewportParams,													// pViewportState;
+		&rasterParams,														// pRasterState;
+		&multisampleParams,													// pMultisampleState;
+		&depthStencilParams,												// pDepthStencilState;
+		&blendParams,														// pColorBlendState;
+		&dynStateParams,													// pDynamicState;
+		0u,																	// flags;
+		pipelineLayout,														// layout;
+		renderPass,															// renderPass;
+		0u,																	// subpass;
+		DE_NULL,															// basePipelineHandle;
+		0u,																	// basePipelineIndex;
+	};
+
+	return vk::createGraphicsPipeline(context.getDeviceInterface(), context.getDevice(), DE_NULL, &pipelineParams);
+}
+
+Move<vk::VkFramebuffer> createFramebuffer (Context& context, vk::VkRenderPass renderPass, vk::VkImageView colorAttView, int width, int height)
+{
+	const vk::VkFramebufferCreateInfo	framebufferParams	=
+	{
+		vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// sType
+		DE_NULL,										// pNext
+		renderPass,										// renderPass
+		1u,												// attachmentCount
+		&colorAttView,									// pAttachments
+		(deUint32)width,								// width
+		(deUint32)height,								// height
+		1u,												// layers
+	};
+
+	return vk::createFramebuffer(context.getDeviceInterface(), context.getDevice(), &framebufferParams);
+}
+
+Move<vk::VkCmdPool> createCmdPool (Context& context)
+{
+	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+	const vk::VkCmdPoolCreateInfo	params				=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,			// sType
+		DE_NULL,											// pNext
+		queueFamilyIndex,									// queueFamilyIndex
+		vk::VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT		// flags
+	};
+
+	return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+Move<vk::VkDescriptorPool> createDescriptorPool (Context& context)
+{
+	return vk::DescriptorPoolBuilder()
+				.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u)
+				.build(context.getDeviceInterface(), context.getDevice(), vk::VK_DESCRIPTOR_POOL_USAGE_DYNAMIC, 1u);
+}
+
+Move<vk::VkCmdBuffer> createCmdBuffer (Context& context, vk::VkCmdPool cmdPool)
+{
+	const vk::VkCmdBufferCreateInfo	params	=
+	{
+		vk::VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,	// sType
+		DE_NULL,										// pNext
+		cmdPool,										// pool
+		vk::VK_CMD_BUFFER_LEVEL_PRIMARY,				// level
+		0u,												// flags
+	};
+
+	return vk::createCommandBuffer(context.getDeviceInterface(), context.getDevice(), &params);
+}
+
+MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
+{
+	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
+	const vk::VkMemoryRequirements	bufReqs	= vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
+	MovePtr<vk::Allocation>			memory	= context.getDefaultAllocator().allocate(bufReqs, memReqs);
+
+	vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
+
+	return memory;
+}
+
+MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkImage image, vk::MemoryRequirement memReqs)
+{
+	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
+	const vk::VkMemoryRequirements	imgReqs	= vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
+	MovePtr<vk::Allocation>			memory	= context.getDefaultAllocator().allocate(imgReqs, memReqs);
+
+	vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
+
+	return memory;
+}
+
+void writeValuesToMem (Context& context, const vk::Allocation& dst, const ValueBufferLayout& layout, const vector<Value>& values, int arrayNdx)
+{
+	copyToLayout(dst.getHostPtr(), layout, values, arrayNdx);
+
+	// \note Buffers are not allocated with coherency / uncached requirement so we need to manually flush CPU write caches
+	flushMappedMemoryRange(context.getDeviceInterface(), context.getDevice(), dst.getMemory(), dst.getOffset(), (vk::VkDeviceSize)layout.size);
+}
+
+vk::VkDescriptorInfo makeUniformBufferBindingInfo (vk::VkBuffer buffer, vk::VkDeviceSize size)
+{
+	const vk::VkDescriptorInfo	info	=
+	{
+		(vk::VkBufferView)0,			// bufferView
+		(vk::VkSampler)0,				// sampler
+		(vk::VkImageView)0,				// imageView
+		vk::VK_IMAGE_LAYOUT_UNDEFINED,	// imageLayout
+		{
+			buffer,							// buffer
+			(vk::VkDeviceSize)0,			// offset
+			size,							// size
+		}								// bufferInfo
+	};
+	return info;
+}
+
+class ShaderCaseInstance : public TestInstance
+{
+public:
+													ShaderCaseInstance		(Context& context, const ShaderCaseSpecification& spec);
+													~ShaderCaseInstance		(void);
+
+	TestStatus										iterate					(void);
+
+private:
+	enum
+	{
+		RENDER_WIDTH		= 64,
+		RENDER_HEIGHT		= 64,
+
+		POSITIONS_OFFSET	= 0,
+		POSITIONS_SIZE		= (int)sizeof(Vec2)*4,
+
+		INDICES_OFFSET		= POSITIONS_SIZE,
+		INDICES_SIZE		= (int)sizeof(deUint16)*6,
+
+		TOTAL_POS_NDX_SIZE	= POSITIONS_SIZE+INDICES_SIZE
+	};
+
+	const ShaderCaseSpecification&					m_spec;
+
+	const Unique<vk::VkBuffer>						m_posNdxBuffer;
+	const UniquePtr<vk::Allocation>					m_posNdxMem;
+
+	const ValueBufferLayout							m_inputLayout;
+	const Unique<vk::VkBuffer>						m_inputBuffer;			// Input values (attributes). Can be NULL if no inputs present
+	const UniquePtr<vk::Allocation>					m_inputMem;				// Input memory, can be NULL if no input buffer exists
+
+	const ValueBufferLayout							m_referenceLayout;
+	const Unique<vk::VkBuffer>						m_referenceBuffer;		// Output (reference) values. Can be NULL if no outputs present
+	const UniquePtr<vk::Allocation>					m_referenceMem;			// Output (reference) memory, can be NULL if no reference buffer exists
+
+	const ValueBufferLayout							m_uniformLayout;
+	const Unique<vk::VkBuffer>						m_uniformBuffer;		// Uniform values. Can be NULL if no uniforms present
+	const UniquePtr<vk::Allocation>					m_uniformMem;			// Uniform memory, can be NULL if no uniform buffer exists
+
+	const Unique<vk::VkBuffer>						m_readImageBuffer;
+	const UniquePtr<vk::Allocation>					m_readImageMem;
+
+	const Unique<vk::VkImage>						m_rtImage;
+	const UniquePtr<vk::Allocation>					m_rtMem;
+	const Unique<vk::VkImageView>					m_rtView;
+
+	const Unique<vk::VkRenderPass>					m_renderPass;
+	const Unique<vk::VkFramebuffer>					m_framebuffer;
+	const PipelineProgram							m_program;
+	const Unique<vk::VkDescriptorSetLayout>			m_descriptorSetLayout;
+	const Unique<vk::VkPipelineLayout>				m_pipelineLayout;
+	const Unique<vk::VkPipeline>					m_pipeline;
+
+	const Unique<vk::VkDescriptorPool>				m_descriptorPool;
+	const Unique<vk::VkDescriptorSet>				m_descriptorSet;
+
+	const Unique<vk::VkCmdPool>						m_cmdPool;
+	const Unique<vk::VkCmdBuffer>					m_cmdBuffer;
+
+	int												m_subCaseNdx;
+};
+
+ShaderCaseInstance::ShaderCaseInstance (Context& context, const ShaderCaseSpecification& spec)
+	: TestInstance			(context)
+	, m_spec				(spec)
+
+	, m_posNdxBuffer		(createBuffer(context, (vk::VkDeviceSize)TOTAL_POS_NDX_SIZE, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT|vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
+	, m_posNdxMem			(allocateAndBindMemory(context, *m_posNdxBuffer, vk::MemoryRequirement::HostVisible))
+
+	, m_inputLayout			(computeStd430Layout(spec.values.inputs))
+	, m_inputBuffer			(m_inputLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_inputLayout.size, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) : Move<vk::VkBuffer>())
+	, m_inputMem			(m_inputLayout.size > 0 ? allocateAndBindMemory(context, *m_inputBuffer, vk::MemoryRequirement::HostVisible) : MovePtr<vk::Allocation>())
+
+	, m_referenceLayout		(computeStd140Layout(spec.values.outputs))
+	, m_referenceBuffer		(m_referenceLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_referenceLayout.size, vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : Move<vk::VkBuffer>())
+	, m_referenceMem		(m_referenceLayout.size > 0 ? allocateAndBindMemory(context, *m_referenceBuffer, vk::MemoryRequirement::HostVisible) : MovePtr<vk::Allocation>())
+
+	, m_uniformLayout		(computeStd140Layout(spec.values.uniforms))
+	, m_uniformBuffer		(m_uniformLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_uniformLayout.size, vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : Move<vk::VkBuffer>())
+	, m_uniformMem			(m_uniformLayout.size > 0 ? allocateAndBindMemory(context, *m_uniformBuffer, vk::MemoryRequirement::HostVisible) : MovePtr<vk::Allocation>())
+
+	, m_readImageBuffer		(createBuffer(context, (vk::VkDeviceSize)(RENDER_WIDTH*RENDER_HEIGHT*4), vk::VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT))
+	, m_readImageMem		(allocateAndBindMemory(context, *m_readImageBuffer, vk::MemoryRequirement::HostVisible))
+
+	, m_rtImage				(createImage2D(context, RENDER_WIDTH, RENDER_HEIGHT, vk::VK_FORMAT_R8G8B8A8_UNORM, vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT))
+	, m_rtMem				(allocateAndBindMemory(context, *m_rtImage, vk::MemoryRequirement::Any))
+	, m_rtView				(createAttachmentView(context, *m_rtImage, vk::VK_FORMAT_R8G8B8A8_UNORM))
+
+	, m_renderPass			(createRenderPass(context, vk::VK_FORMAT_R8G8B8A8_UNORM))
+	, m_framebuffer			(createFramebuffer(context, *m_renderPass, *m_rtView, RENDER_WIDTH, RENDER_HEIGHT))
+	, m_program				(context, spec)
+	, m_descriptorSetLayout	(createDescriptorSetLayout(context, m_program.getStages()))
+	, m_pipelineLayout		(createPipelineLayout(context, *m_descriptorSetLayout))
+	, m_pipeline			(createPipeline(context, spec.values.inputs, m_inputLayout, m_program, *m_renderPass, *m_pipelineLayout, tcu::IVec2(RENDER_WIDTH, RENDER_HEIGHT)))
+
+	, m_descriptorPool		(createDescriptorPool(context))
+	, m_descriptorSet		(vk::allocDescriptorSet(context.getDeviceInterface(), context.getDevice(), *m_descriptorPool, vk::VK_DESCRIPTOR_SET_USAGE_STATIC, *m_descriptorSetLayout))
+
+	, m_cmdPool				(createCmdPool(context))
+	, m_cmdBuffer			(createCmdBuffer(context, *m_cmdPool))
+
+	, m_subCaseNdx			(0)
+{
+	const vk::DeviceInterface&	vkd					= context.getDeviceInterface();
+	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
+
+	{
+		const Vec2			s_positions[]	=
+		{
+			Vec2(-1.0f, -1.0f),
+			Vec2(-1.0f, +1.0f),
+			Vec2(+1.0f, -1.0f),
+			Vec2(+1.0f, +1.0f)
+		};
+		const deUint16		s_indices[]		=
+		{
+			0, 1, 2,
+			1, 3, 2
+		};
+
+		DE_STATIC_ASSERT(sizeof(s_positions) == POSITIONS_SIZE);
+		DE_STATIC_ASSERT(sizeof(s_indices) == INDICES_SIZE);
+
+		deMemcpy((deUint8*)m_posNdxMem->getHostPtr() + POSITIONS_OFFSET,	&s_positions[0],	sizeof(s_positions));
+		deMemcpy((deUint8*)m_posNdxMem->getHostPtr() + INDICES_OFFSET,		&s_indices[0],		sizeof(s_indices));
+
+		flushMappedMemoryRange(m_context.getDeviceInterface(), context.getDevice(), m_posNdxMem->getMemory(), m_posNdxMem->getOffset(), sizeof(s_positions)+sizeof(s_indices));
+	}
+
+	if (!m_spec.values.uniforms.empty())
+	{
+		const vk::VkDescriptorInfo	descInfo	= makeUniformBufferBindingInfo(*m_uniformBuffer, (vk::VkDeviceSize)m_uniformLayout.size);
+
+		vk::DescriptorSetUpdateBuilder()
+			.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(USER_UNIFORM_BINDING),
+						 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descInfo)
+			.update(vkd, m_context.getDevice());
+	}
+
+	if (!m_spec.values.outputs.empty())
+	{
+		const vk::VkDescriptorInfo	descInfo	= makeUniformBufferBindingInfo(*m_referenceBuffer, (vk::VkDeviceSize)m_referenceLayout.size);
+
+		vk::DescriptorSetUpdateBuilder()
+			.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(REFERENCE_UNIFORM_BINDING),
+						 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descInfo)
+			.update(vkd, m_context.getDevice());
+	}
+
+	// Record command buffer
+
+	{
+		const vk::VkCmdBufferBeginInfo beginInfo	=
+		{
+			vk::VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,	// sType
+			DE_NULL,										// pNext
+			0u,												// flags
+			(vk::VkRenderPass)0,							// renderPass
+			0u,												// subpass
+			(vk::VkFramebuffer)0,							// framebuffer
+		};
+
+		VK_CHECK(vkd.beginCommandBuffer(*m_cmdBuffer, &beginInfo));
+	}
+
+	{
+		const vk::VkMemoryBarrier		vertFlushBarrier	=
+		{
+			vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,													// sType
+			DE_NULL,																				// pNext
+			vk::VK_MEMORY_OUTPUT_HOST_WRITE_BIT,													// outputMask
+			vk::VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT|vk::VK_MEMORY_INPUT_UNIFORM_READ_BIT,	// inputMask
+		};
+		const vk::VkImageMemoryBarrier	colorAttBarrier		=
+		{
+			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// sType
+			DE_NULL,										// pNext
+			0u,												// outputMask
+			vk::VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT,		// inputMask
+			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// oldLayout
+			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// newLayout
+			queueFamilyIndex,								// srcQueueFamilyIndex
+			queueFamilyIndex,								// destQueueFamilyIndex
+			*m_rtImage,										// image
+			{
+				vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
+				0u,												// baseMipLevel
+				1u,												// mipLevels
+				0u,												// baseArraySlice
+				1u,												// arraySize
+			}												// subresourceRange
+		};
+		const void* const				barriers[]			= { &vertFlushBarrier, &colorAttBarrier };
+
+		vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_ALL_GPU_COMMANDS,
+							   DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	{
+		const vk::VkClearValue			clearValue		= vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
+		const vk::VkRenderPassBeginInfo	passBeginInfo	=
+		{
+			vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// sType
+			DE_NULL,										// pNext
+			*m_renderPass,									// renderPass
+			*m_framebuffer,									// framebuffer
+			{ { 0, 0 }, { RENDER_WIDTH, RENDER_HEIGHT } },	// renderArea
+			1u,												// clearValueCount
+			&clearValue,									// pClearValues
+		};
+
+		vkd.cmdBeginRenderPass(*m_cmdBuffer, &passBeginInfo, vk::VK_RENDER_PASS_CONTENTS_INLINE);
+	}
+
+	vkd.cmdBindPipeline			(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
+	vkd.cmdBindDescriptorSets	(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &*m_descriptorSet, 0u, DE_NULL);
+
+	{
+		const vk::VkBuffer		buffers[]	= { *m_posNdxBuffer, *m_inputBuffer };
+		const vk::VkDeviceSize	offsets[]	= { POSITIONS_OFFSET, 0u };
+		const deUint32			numBuffers	= buffers[1] != 0 ? 2u : 1u;
+		vkd.cmdBindVertexBuffers(*m_cmdBuffer, 0u, numBuffers, buffers, offsets);
+	}
+
+	vkd.cmdBindIndexBuffer	(*m_cmdBuffer, *m_posNdxBuffer, (vk::VkDeviceSize)INDICES_OFFSET, vk::VK_INDEX_TYPE_UINT16);
+	vkd.cmdDrawIndexed		(*m_cmdBuffer, 6u, 1u, 0u, 0u, 0u);
+	vkd.cmdEndRenderPass	(*m_cmdBuffer);
+
+	{
+		const vk::VkImageMemoryBarrier	renderFinishBarrier	=
+		{
+			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// sType
+			DE_NULL,										// pNext
+			vk::VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,		// outputMask
+			vk::VK_MEMORY_INPUT_TRANSFER_BIT,				// inputMask
+			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// oldLayout
+			vk::VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,	// newLayout
+			queueFamilyIndex,								// srcQueueFamilyIndex
+			queueFamilyIndex,								// destQueueFamilyIndex
+			*m_rtImage,										// image
+			{
+				vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
+				0u,												// baseMipLevel
+				1u,												// mipLevels
+				0u,												// baseArraySlice
+				1u,												// arraySize
+			}												// subresourceRange
+		};
+		const void* const				barriers[]			= { &renderFinishBarrier };
+
+		vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
+							   DE_FALSE, DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	{
+		const vk::VkBufferImageCopy	copyParams	=
+		{
+			(vk::VkDeviceSize)0u,					// bufferOffset
+			(deUint32)RENDER_WIDTH,					// bufferRowLength
+			(deUint32)RENDER_HEIGHT,				// bufferImageHeight
+			{
+				vk::VK_IMAGE_ASPECT_COLOR,				// aspect
+				0u,										// mipLevel
+				0u,										// arrayLayer
+				1u,										// arraySize
+			},										// imageSubresource
+			{ 0u, 0u, 0u },							// imageOffset
+			{ RENDER_WIDTH, RENDER_HEIGHT, 1u }		// imageExtent
+		};
+
+		vkd.cmdCopyImageToBuffer(*m_cmdBuffer, *m_rtImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, *m_readImageBuffer, 1u, &copyParams);
+	}
+
+	{
+		const vk::VkBufferMemoryBarrier	copyFinishBarrier	=
+		{
+			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// sType
+			DE_NULL,											// pNext
+			vk::VK_MEMORY_OUTPUT_TRANSFER_BIT,					// outputMask
+			vk::VK_MEMORY_INPUT_HOST_READ_BIT,					// inputMask
+			queueFamilyIndex,									// srcQueueFamilyIndex
+			queueFamilyIndex,									// destQueueFamilyIndex
+			*m_readImageBuffer,									// buffer
+			0u,													// offset
+			(vk::VkDeviceSize)(RENDER_WIDTH*RENDER_HEIGHT*4)	// size
+		};
+		const void* const				barriers[]			= { &copyFinishBarrier };
+
+		vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT,
+							   DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
+	}
+
+	VK_CHECK(vkd.endCommandBuffer(*m_cmdBuffer));
+}
+
+ShaderCaseInstance::~ShaderCaseInstance (void)
+{
+}
+
+int getNumSubCases (const ValueBlock& values)
+{
+	if (!values.outputs.empty())
+		return int(values.outputs[0].elements.size() / values.outputs[0].type.getScalarSize());
+	else
+		return 1; // Always run at least one iteration even if no output values are specified
+}
+
+bool checkResultImage (const ConstPixelBufferAccess& result)
+{
+	const tcu::IVec4	refPix	(255, 255, 255, 255);
+
+	for (int y = 0; y < result.getHeight(); y++)
+	{
+		for (int x = 0; x < result.getWidth(); x++)
+		{
+			const tcu::IVec4	resPix	= result.getPixelInt(x, y);
+
+			if (boolAny(notEqual(resPix, refPix)))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+TestStatus ShaderCaseInstance::iterate (void)
+{
+	const vk::DeviceInterface&	vkd		= m_context.getDeviceInterface();
+	const vk::VkDevice			device	= m_context.getDevice();
+	const vk::VkQueue			queue	= m_context.getUniversalQueue();
+
+	if (!m_spec.values.inputs.empty())
+		writeValuesToMem(m_context, *m_inputMem, m_inputLayout, m_spec.values.inputs, m_subCaseNdx);
+
+	if (!m_spec.values.outputs.empty())
+		writeValuesToMem(m_context, *m_referenceMem, m_referenceLayout, m_spec.values.outputs, m_subCaseNdx);
+
+	if (!m_spec.values.uniforms.empty())
+		writeValuesToMem(m_context, *m_uniformMem, m_uniformLayout, m_spec.values.uniforms, m_subCaseNdx);
+
+	{
+		const vk::VkFenceCreateInfo	fenceParams	=
+		{
+			vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// sType
+			DE_NULL,									// pNext
+			0u,											// flags
+		};
+		const Unique<vk::VkFence>	fence		(vk::createFence(vkd, device, &fenceParams));
+
+		VK_CHECK(vkd.queueSubmit	(queue, 1u, &m_cmdBuffer.get(), *fence));
+		VK_CHECK(vkd.waitForFences	(device, 1u, &fence.get(), DE_TRUE, ~0ull));
+	}
+
+	{
+		const ConstPixelBufferAccess	imgAccess	(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), RENDER_WIDTH, RENDER_HEIGHT, 1, m_readImageMem->getHostPtr());
+
+		invalidateMappedMemoryRange(vkd, device, m_readImageMem->getMemory(), m_readImageMem->getOffset(), (vk::VkDeviceSize)(RENDER_WIDTH*RENDER_HEIGHT*4));
+
+		if (!checkResultImage(imgAccess))
+		{
+			TestLog&	log		= m_context.getTestContext().getLog();
+
+			log << TestLog::Message << "ERROR: Got non-white pixels on sub-case " << m_subCaseNdx << TestLog::EndMessage
+				<< TestLog::Image("Result", "Result", imgAccess);
+
+			dumpValues(log, m_spec.values, m_subCaseNdx);
+
+			return TestStatus::fail(string("Got invalid pixels at sub-case ") + de::toString(m_subCaseNdx));
+		}
+	}
+
+	if (++m_subCaseNdx < getNumSubCases(m_spec.values))
+		return TestStatus::incomplete();
+	else
+		return TestStatus::pass("All sub-cases passed");
+}
+
+class ShaderCase : public TestCase
+{
+public:
+									ShaderCase		(tcu::TestContext& testCtx, const string& name, const string& description, const ShaderCaseSpecification& spec);
+
+
+	void							initPrograms	(SourceCollections& programCollection) const;
+	TestInstance*					createInstance	(Context& context) const;
+
+private:
+	const ShaderCaseSpecification	m_spec;
+};
+
+ShaderCase::ShaderCase (tcu::TestContext& testCtx, const string& name, const string& description, const ShaderCaseSpecification& spec)
+	: TestCase	(testCtx, name, description)
+	, m_spec	(spec)
+{
+}
+
+void ShaderCase::initPrograms (SourceCollections& sourceCollection) const
+{
+	vector<ProgramSources>	specializedSources	(m_spec.programs.size());
+
+	DE_ASSERT(isValid(m_spec));
+
+	if (m_spec.expectResult != glu::sl::EXPECT_PASS)
+		TCU_THROW(InternalError, "Only EXPECT_PASS is supported");
+
+	if (m_spec.caseType == glu::sl::CASETYPE_VERTEX_ONLY)
+	{
+		DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[glu::SHADERTYPE_VERTEX].size() == 1);
+		specializedSources[0] << glu::VertexSource(specializeVertexShader(m_spec, m_spec.programs[0].sources.sources[glu::SHADERTYPE_VERTEX][0]))
+							  << glu::FragmentSource(genFragmentShader(m_spec));
+	}
+	else if (m_spec.caseType == glu::sl::CASETYPE_FRAGMENT_ONLY)
+	{
+		DE_ASSERT(m_spec.programs.size() == 1 && m_spec.programs[0].sources.sources[glu::SHADERTYPE_FRAGMENT].size() == 1);
+		specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
+							  << glu::FragmentSource(specializeFragmentShader(m_spec, m_spec.programs[0].sources.sources[glu::SHADERTYPE_FRAGMENT][0]));
+	}
+	else
+	{
+		DE_ASSERT(m_spec.caseType == glu::sl::CASETYPE_COMPLETE);
+
+		const int	maxPatchVertices	= 4; // \todo [2015-08-05 pyry] Query
+
+		for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
+		{
+			const ProgramSpecializationParams	progSpecParams	(m_spec, m_spec.programs[progNdx].requiredExtensions, maxPatchVertices);
+
+			specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
+		}
+	}
+
+	for (size_t progNdx = 0; progNdx < specializedSources.size(); progNdx++)
+	{
+		for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+		{
+			if (!specializedSources[progNdx].sources[shaderType].empty())
+			{
+				glu::ProgramSources& curSrc	= sourceCollection.glslSources.add(getShaderName((glu::ShaderType)shaderType, progNdx));
+				curSrc.sources[shaderType] = specializedSources[progNdx].sources[shaderType];
+			}
+		}
+	}
+}
+
+TestInstance* ShaderCase::createInstance (Context& context) const
+{
+	return new ShaderCaseInstance(context, m_spec);
+}
+
+class ShaderCaseFactory : public glu::sl::ShaderCaseFactory
+{
+public:
+	ShaderCaseFactory (tcu::TestContext& testCtx)
+		: m_testCtx(testCtx)
+	{
+	}
+
+	tcu::TestCaseGroup* createGroup (const string& name, const string& description, const vector<tcu::TestNode*>& children)
+	{
+		return new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
+	}
+
+	tcu::TestCase* createCase (const string& name, const string& description, const ShaderCaseSpecification& spec)
+	{
+		return new ShaderCase(m_testCtx, name, description, spec);
+	}
+
+private:
+	tcu::TestContext&	m_testCtx;
+};
+
+class ShaderLibraryGroup : public tcu::TestCaseGroup
+{
+public:
+	ShaderLibraryGroup (tcu::TestContext& testCtx, const string& name, const string& description, const string& filename)
+		 : tcu::TestCaseGroup	(testCtx, name.c_str(), description.c_str())
+		 , m_filename			(filename)
+	{
+	}
+
+	void init (void)
+	{
+		ShaderCaseFactory				caseFactory	(m_testCtx);
+		const vector<tcu::TestNode*>	children	= glu::sl::parseFile(m_testCtx.getArchive(), m_filename, &caseFactory);
+
+		for (size_t ndx = 0; ndx < children.size(); ndx++)
+		{
+			try
+			{
+				addChild(children[ndx]);
+			}
+			catch (...)
+			{
+				for (; ndx < children.size(); ndx++)
+					delete children[ndx];
+				throw;
+			}
+		}
+	}
+
+private:
+	const string	m_filename;
+};
+
+} // anonymous
+
+MovePtr<tcu::TestCaseGroup> createShaderLibraryGroup (tcu::TestContext& testCtx, const string& name, const string& description, const string& filename)
+{
+	return MovePtr<tcu::TestCaseGroup>(new ShaderLibraryGroup(testCtx, name, description, filename));
+}
+
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/vktShaderLibrary.hpp b/external/vulkancts/modules/vulkan/vktShaderLibrary.hpp
new file mode 100644
index 0000000..17542a4
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktShaderLibrary.hpp
@@ -0,0 +1,48 @@
+#ifndef _VKTSHADERLIBRARY_HPP
+#define _VKTSHADERLIBRARY_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief ShaderLibrary Vulkan implementation
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+#include "deUniquePtr.hpp"
+
+namespace vkt
+{
+
+de::MovePtr<tcu::TestCaseGroup>		createShaderLibraryGroup	(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const std::string& filename);
+
+} // vkt
+
+#endif // _VKTSHADERLIBRARY_HPP
diff --git a/external/vulkancts/modules/vulkan/vktTestCase.cpp b/external/vulkancts/modules/vulkan/vktTestCase.cpp
new file mode 100644
index 0000000..b813f23
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestCase.cpp
@@ -0,0 +1,194 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan test case base classes
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPlatform.hpp"
+
+#include "deMemory.h"
+
+namespace vkt
+{
+
+// Default device utilities
+
+using std::vector;
+using namespace vk;
+
+static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
+{
+	const vector<VkQueueFamilyProperties>	queueProps	= getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
+
+	for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
+	{
+		if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
+			return (deUint32)queueNdx;
+	}
+
+	TCU_THROW(NotSupportedError, "No matching queue found");
+}
+
+// \todo [2015-09-28 pyry] Refactor using Move<>
+
+struct DeviceCreateInfoHelper
+{
+	VkPhysicalDeviceFeatures	enabledFeatures;
+	VkDeviceQueueCreateInfo		queueInfo;
+	VkDeviceCreateInfo			deviceInfo;
+
+	DeviceCreateInfoHelper (deUint32 queueIndex)
+	{
+		deMemset(&enabledFeatures,	0, sizeof(enabledFeatures));
+		deMemset(&queueInfo,		0, sizeof(queueInfo));
+		deMemset(&deviceInfo,		0, sizeof(deviceInfo));
+
+		// \todo [2015-07-09 pyry] What's the policy for enabling features?
+		//  * Enable all supported by default, and expose that to test cases
+		//  * More limited enabled set could be used for verifying that tests behave correctly
+
+		queueInfo.sType						= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+		queueInfo.pNext						= DE_NULL;
+		queueInfo.queueFamilyIndex			= queueIndex;
+		queueInfo.queueCount				= 1u;
+
+		deviceInfo.sType					= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+		deviceInfo.pNext					= DE_NULL;
+		deviceInfo.queueRecordCount			= 1u;
+		deviceInfo.pRequestedQueues			= &queueInfo;
+		deviceInfo.extensionCount			= 0u;
+		deviceInfo.ppEnabledExtensionNames	= DE_NULL;
+		deviceInfo.pEnabledFeatures			= &enabledFeatures;
+	}
+};
+
+class DefaultDevice
+{
+public:
+									DefaultDevice					(const PlatformInterface& vkPlatform, const tcu::CommandLine& cmdLine);
+									~DefaultDevice					(void);
+
+	VkInstance						getInstance						(void) const	{ return *m_instance;					}
+	const InstanceInterface&		getInstanceInterface			(void) const	{ return m_instanceInterface;			}
+
+	VkPhysicalDevice				getPhysicalDevice				(void) const	{ return m_physicalDevice;				}
+
+	VkDevice						getDevice						(void) const	{ return *m_device;						}
+	const DeviceInterface&			getDeviceInterface				(void) const	{ return m_deviceInterface;				}
+
+	deUint32						getUniversalQueueFamilyIndex	(void) const	{ return m_universalQueueFamilyIndex;	}
+	VkQueue							getUniversalQueue				(void) const;
+
+private:
+	const Unique<VkInstance>		m_instance;
+	const InstanceDriver			m_instanceInterface;
+
+	const VkPhysicalDevice			m_physicalDevice;
+
+	const deUint32					m_universalQueueFamilyIndex;
+	const DeviceCreateInfoHelper	m_deviceCreateInfo;
+
+	const Unique<VkDevice>			m_device;
+	const DeviceDriver				m_deviceInterface;
+};
+
+DefaultDevice::DefaultDevice (const PlatformInterface& vkPlatform, const tcu::CommandLine& cmdLine)
+	: m_instance					(createDefaultInstance(vkPlatform))
+	, m_instanceInterface			(vkPlatform, *m_instance)
+	, m_physicalDevice				(chooseDevice(m_instanceInterface, *m_instance, cmdLine))
+	, m_universalQueueFamilyIndex	(findQueueFamilyIndexWithCaps(m_instanceInterface, m_physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT))
+	, m_deviceCreateInfo			(m_universalQueueFamilyIndex)
+	, m_device						(createDevice(m_instanceInterface, m_physicalDevice, &m_deviceCreateInfo.deviceInfo))
+	, m_deviceInterface				(m_instanceInterface, *m_device)
+{
+}
+
+DefaultDevice::~DefaultDevice (void)
+{
+}
+
+VkQueue DefaultDevice::getUniversalQueue (void) const
+{
+	VkQueue	queue	= 0;
+	VK_CHECK(m_deviceInterface.getDeviceQueue(*m_device, m_universalQueueFamilyIndex, 0, &queue));
+	return queue;
+}
+
+// Allocator utilities
+
+vk::Allocator* createAllocator (DefaultDevice* device)
+{
+	const VkPhysicalDeviceMemoryProperties memoryProperties = vk::getPhysicalDeviceMemoryProperties(device->getInstanceInterface(), device->getPhysicalDevice());
+
+	// \todo [2015-07-24 jarkko] support allocator selection/configuration from command line (or compile time)
+	return new SimpleAllocator(device->getDeviceInterface(), device->getDevice(), memoryProperties);
+}
+
+// Context
+
+Context::Context (tcu::TestContext&							testCtx,
+				  const vk::PlatformInterface&				platformInterface,
+				  vk::ProgramCollection<vk::ProgramBinary>&	progCollection)
+	: m_testCtx				(testCtx)
+	, m_platformInterface	(platformInterface)
+	, m_progCollection		(progCollection)
+	, m_device				(new DefaultDevice(m_platformInterface, testCtx.getCommandLine()))
+	, m_allocator			(createAllocator(m_device.get()))
+{
+}
+
+Context::~Context (void)
+{
+}
+
+vk::VkInstance					Context::getInstance					(void) const { return m_device->getInstance();					}
+const vk::InstanceInterface&	Context::getInstanceInterface			(void) const { return m_device->getInstanceInterface();			}
+vk::VkPhysicalDevice			Context::getPhysicalDevice				(void) const { return m_device->getPhysicalDevice();			}
+vk::VkDevice					Context::getDevice						(void) const { return m_device->getDevice();					}
+const vk::DeviceInterface&		Context::getDeviceInterface				(void) const { return m_device->getDeviceInterface();			}
+deUint32						Context::getUniversalQueueFamilyIndex	(void) const { return m_device->getUniversalQueueFamilyIndex();	}
+vk::VkQueue						Context::getUniversalQueue				(void) const { return m_device->getUniversalQueue();			}
+vk::Allocator&					Context::getDefaultAllocator			(void) const { return *m_allocator;							}
+
+// TestCase
+
+void TestCase::initPrograms (SourceCollections&) const
+{
+}
+
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/vktTestCase.hpp b/external/vulkancts/modules/vulkan/vktTestCase.hpp
new file mode 100644
index 0000000..e9b5659
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestCase.hpp
@@ -0,0 +1,141 @@
+#ifndef _VKTTESTCASE_HPP
+#define _VKTTESTCASE_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan test case base classes
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+#include "vkDefs.hpp"
+#include "deUniquePtr.hpp"
+
+namespace glu
+{
+struct ProgramSources;
+}
+
+namespace vk
+{
+class PlatformInterface;
+class ProgramBinary;
+template<typename Program> class ProgramCollection;
+class Allocator;
+struct SourceCollections;
+}
+
+namespace vkt
+{
+
+class DefaultDevice;
+
+class Context
+{
+public:
+												Context							(tcu::TestContext&							testCtx,
+																				 const vk::PlatformInterface&				platformInterface,
+																				 vk::ProgramCollection<vk::ProgramBinary>&	progCollection);
+												~Context						(void);
+
+	tcu::TestContext&							getTestContext					(void) const { return m_testCtx;			}
+	const vk::PlatformInterface&				getPlatformInterface			(void) const { return m_platformInterface;	}
+	vk::ProgramCollection<vk::ProgramBinary>&	getBinaryCollection				(void) const { return m_progCollection;		}
+
+	// Default instance & device, selected with --deqp-vk-device-id=N
+	vk::VkInstance								getInstance						(void) const;
+	const vk::InstanceInterface&				getInstanceInterface			(void) const;
+	vk::VkPhysicalDevice						getPhysicalDevice				(void) const;
+	vk::VkDevice								getDevice						(void) const;
+	const vk::DeviceInterface&					getDeviceInterface				(void) const;
+	deUint32									getUniversalQueueFamilyIndex	(void) const;
+	vk::VkQueue									getUniversalQueue				(void) const;
+
+	vk::Allocator&								getDefaultAllocator				(void) const;
+
+protected:
+	tcu::TestContext&							m_testCtx;
+	const vk::PlatformInterface&				m_platformInterface;
+	vk::ProgramCollection<vk::ProgramBinary>&	m_progCollection;
+
+	const de::UniquePtr<DefaultDevice>			m_device;
+	const de::UniquePtr<vk::Allocator>			m_allocator;
+
+private:
+												Context							(const Context&); // Not allowed
+	Context&									operator=						(const Context&); // Not allowed
+};
+
+
+class TestInstance;
+
+class TestCase : public tcu::TestCase
+{
+public:
+							TestCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description);
+							TestCase		(tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& description);
+	virtual					~TestCase		(void) {}
+
+	virtual void			initPrograms	(vk::SourceCollections& programCollection) const;
+	virtual TestInstance*	createInstance	(Context& context) const = 0;
+
+	IterateResult			iterate			(void) { DE_ASSERT(false); return STOP; } // Deprecated in this module
+};
+
+class TestInstance
+{
+public:
+								TestInstance	(Context& context) : m_context(context) {}
+	virtual						~TestInstance	(void) {}
+
+	virtual tcu::TestStatus		iterate			(void) = 0;
+
+protected:
+	Context&					m_context;
+
+private:
+								TestInstance	(const TestInstance&);
+	TestInstance&				operator=		(const TestInstance&);
+};
+
+inline TestCase::TestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
+	: tcu::TestCase(testCtx, name.c_str(), description.c_str())
+{
+}
+
+inline TestCase::TestCase (tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& description)
+	: tcu::TestCase(testCtx, type, name.c_str(), description.c_str())
+{
+}
+
+} // vkt
+
+#endif // _VKTTESTCASE_HPP
diff --git a/external/vulkancts/modules/vulkan/vktTestCaseUtil.cpp b/external/vulkancts/modules/vulkan/vktTestCaseUtil.cpp
new file mode 100644
index 0000000..7d63796
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestCaseUtil.cpp
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief TestCase utilities
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCaseUtil.hpp"
+
+DE_EMPTY_CPP_FILE
diff --git a/external/vulkancts/modules/vulkan/vktTestCaseUtil.hpp b/external/vulkancts/modules/vulkan/vktTestCaseUtil.hpp
new file mode 100644
index 0000000..1fa09d3
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestCaseUtil.hpp
@@ -0,0 +1,257 @@
+#ifndef _VKTTESTCASEUTIL_HPP
+#define _VKTTESTCASEUTIL_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief TestCase utilities
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+
+template<typename Arg0>
+struct NoPrograms1
+{
+	void	init	(vk::SourceCollections&, Arg0) const {}
+};
+
+template<typename Instance, typename Arg0, typename Programs = NoPrograms1<Arg0> >
+class InstanceFactory1 : public TestCase
+{
+public:
+					InstanceFactory1	(tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& desc, const Arg0& arg0)
+						: TestCase	(testCtx, type, name, desc)
+						, m_progs	()
+						, m_arg0	(arg0)
+					{}
+
+					InstanceFactory1	(tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& desc, const Programs& progs, const Arg0& arg0)
+						: TestCase	(testCtx, type, name, desc)
+						, m_progs	(progs)
+						, m_arg0	(arg0)
+					{}
+
+	void			initPrograms		(vk::SourceCollections& dst) const { m_progs.init(dst, m_arg0); }
+	TestInstance*	createInstance		(Context& context) const { return new Instance(context, m_arg0); }
+
+private:
+	const Programs	m_progs;
+	const Arg0		m_arg0;
+};
+
+class FunctionInstance0 : public TestInstance
+{
+public:
+	typedef tcu::TestStatus	(*Function)	(Context& context);
+
+					FunctionInstance0	(Context& context, Function function)
+						: TestInstance	(context)
+						, m_function	(function)
+					{}
+
+	tcu::TestStatus	iterate				(void) { return m_function(m_context); }
+
+private:
+	const Function	m_function;
+};
+
+template<typename Arg0>
+class FunctionInstance1 : public TestInstance
+{
+public:
+	typedef tcu::TestStatus	(*Function)	(Context& context, Arg0 arg0);
+
+	struct Args
+	{
+		Args (Function func_, Arg0 arg0_) : func(func_), arg0(arg0_) {}
+
+		Function	func;
+		Arg0		arg0;
+	};
+
+					FunctionInstance1	(Context& context, const Args& args)
+						: TestInstance	(context)
+						, m_args		(args)
+					{}
+
+	tcu::TestStatus	iterate				(void) { return m_args.func(m_context, m_args.arg0); }
+
+private:
+	const Args		m_args;
+};
+
+class FunctionPrograms0
+{
+public:
+	typedef void	(*Function)		(vk::SourceCollections& dst);
+
+					FunctionPrograms0	(Function func)
+						: m_func(func)
+					{}
+
+	void			init			(vk::SourceCollections& dst, FunctionInstance0::Function) const { m_func(dst); }
+
+private:
+	const Function	m_func;
+};
+
+template<typename Arg0>
+class FunctionPrograms1
+{
+public:
+	typedef void	(*Function)		(vk::SourceCollections& dst, Arg0 arg0);
+
+					FunctionPrograms1	(Function func)
+						: m_func(func)
+					{}
+
+	void			init			(vk::SourceCollections& dst, const typename FunctionInstance1<Arg0>::Args& args) const { m_func(dst, args.arg0); }
+
+private:
+	const Function	m_func;
+};
+
+// createFunctionCase
+
+inline TestCase* createFunctionCase (tcu::TestContext&				testCtx,
+									 tcu::TestNodeType				type,
+									 const std::string&				name,
+									 const std::string&				desc,
+									 FunctionInstance0::Function	testFunction)
+{
+	return new InstanceFactory1<FunctionInstance0, FunctionInstance0::Function>(testCtx, type, name, desc, testFunction);
+}
+
+inline TestCase* createFunctionCaseWithPrograms (tcu::TestContext&				testCtx,
+												 tcu::TestNodeType				type,
+												 const std::string&				name,
+												 const std::string&				desc,
+												 FunctionPrograms0::Function	initPrograms,
+												 FunctionInstance0::Function	testFunction)
+{
+	return new InstanceFactory1<FunctionInstance0, FunctionInstance0::Function, FunctionPrograms0>(
+		testCtx, type, name, desc, FunctionPrograms0(initPrograms), testFunction);
+}
+
+template<typename Arg0>
+TestCase* createFunctionCase (tcu::TestContext&								testCtx,
+							  tcu::TestNodeType								type,
+							  const std::string&							name,
+							  const std::string&							desc,
+							  typename FunctionInstance1<Arg0>::Function	testFunction,
+							  Arg0											arg0)
+{
+	return new InstanceFactory1<FunctionInstance1<Arg0>, typename FunctionInstance1<Arg0>::Args>(
+		testCtx, type, name, desc, typename FunctionInstance1<Arg0>::Args(testFunction, arg0));
+}
+
+template<typename Arg0>
+TestCase* createFunctionCaseWithPrograms (tcu::TestContext&								testCtx,
+										  tcu::TestNodeType								type,
+										  const std::string&							name,
+										  const std::string&							desc,
+										  typename FunctionPrograms1<Arg0>::Function	initPrograms,
+										  typename FunctionInstance1<Arg0>::Function	testFunction,
+										  Arg0											arg0)
+{
+	return new InstanceFactory1<FunctionInstance1<Arg0>, typename FunctionInstance1<Arg0>::Args, FunctionPrograms1<Arg0> >(
+		testCtx, type, name, desc, FunctionPrograms1<Arg0>(initPrograms), typename FunctionInstance1<Arg0>::Args(testFunction, arg0));
+}
+
+// addFunctionCase
+
+inline void addFunctionCase (tcu::TestCaseGroup*			group,
+							 const std::string&				name,
+							 const std::string&				desc,
+							 FunctionInstance0::Function	testFunc)
+{
+	group->addChild(createFunctionCase(group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, testFunc));
+}
+
+inline void addFunctionCaseWithPrograms (tcu::TestCaseGroup*			group,
+										 const std::string&				name,
+										 const std::string&				desc,
+										 FunctionPrograms0::Function	initPrograms,
+										 FunctionInstance0::Function	testFunc)
+{
+	group->addChild(createFunctionCaseWithPrograms(group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, initPrograms, testFunc));
+}
+
+template<typename Arg0>
+void addFunctionCase (tcu::TestCaseGroup*							group,
+					  const std::string&							name,
+					  const std::string&							desc,
+					  typename FunctionInstance1<Arg0>::Function	testFunc,
+					  Arg0											arg0)
+{
+	group->addChild(createFunctionCase<Arg0>(group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, testFunc, arg0));
+}
+
+template<typename Arg0>
+void addFunctionCase (tcu::TestCaseGroup*							group,
+					  tcu::TestNodeType								type,
+					  const std::string&							name,
+					  const std::string&							desc,
+					  typename FunctionInstance1<Arg0>::Function	testFunc,
+					  Arg0											arg0)
+{
+	group->addChild(createFunctionCase<Arg0>(group->getTestContext(), type, name, desc, testFunc, arg0));
+}
+
+template<typename Arg0>
+void addFunctionCaseWithPrograms (tcu::TestCaseGroup*							group,
+								  const std::string&							name,
+								  const std::string&							desc,
+								  typename FunctionPrograms1<Arg0>::Function	initPrograms,
+								  typename FunctionInstance1<Arg0>::Function	testFunc,
+								  Arg0											arg0)
+{
+	group->addChild(createFunctionCaseWithPrograms<Arg0>(group->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, initPrograms, testFunc, arg0));
+}
+
+template<typename Arg0>
+void addFunctionCaseWithPrograms (tcu::TestCaseGroup*							group,
+								  tcu::TestNodeType								type,
+								  const std::string&							name,
+								  const std::string&							desc,
+								  typename FunctionPrograms1<Arg0>::Function	initPrograms,
+								  typename FunctionInstance1<Arg0>::Function	testFunc,
+								  Arg0											arg0)
+{
+	group->addChild(createFunctionCaseWithPrograms<Arg0>(group->getTestContext(), type, name, desc, initPrograms, testFunc, arg0));
+}
+
+} // vkt
+
+#endif // _VKTTESTCASEUTIL_HPP
diff --git a/external/vulkancts/modules/vulkan/vktTestPackage.cpp b/external/vulkancts/modules/vulkan/vktTestPackage.cpp
new file mode 100644
index 0000000..c1e329c
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestPackage.cpp
@@ -0,0 +1,290 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan Test Package
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestPackage.hpp"
+
+#include "tcuPlatform.hpp"
+#include "tcuTestCase.hpp"
+#include "tcuTestLog.hpp"
+
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkBinaryRegistry.hpp"
+#include "vkGlslToSpirV.hpp"
+#include "vkSpirVAsm.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include "vktInfo.hpp"
+#include "vktApiTests.hpp"
+#include "vktPipelineTests.hpp"
+#include "vktBindingModelTests.hpp"
+#include "vktSpvAsmTests.hpp"
+#include "vktShaderLibrary.hpp"
+#include "vktRenderPassTests.hpp"
+
+#include <vector>
+#include <sstream>
+
+namespace // compilation
+{
+
+vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
+{
+	return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
+}
+
+vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
+{
+	return vk::assembleProgram(source, buildInfo);
+}
+
+template <typename InfoType, typename IteratorType>
+vk::ProgramBinary* buildProgram (const std::string& casePath, IteratorType iter, vkt::Context* context, vk::BinaryCollection* progCollection)
+{
+	tcu::TestLog&					log			= context->getTestContext().getLog();
+	const vk::ProgramIdentifier		progId		(casePath, iter.getName());
+	const tcu::ScopedLogSection		progSection	(log, iter.getName(), "Program: " + iter.getName());
+	de::MovePtr<vk::ProgramBinary>	binProg;
+	InfoType						buildInfo;
+
+	try
+	{
+		binProg	= de::MovePtr<vk::ProgramBinary>(compileProgram(iter.getProgram(), &buildInfo));
+		log << buildInfo;
+	}
+	catch (const tcu::NotSupportedError& err)
+	{
+		// Try to load from cache
+		const vk::BinaryRegistryReader	registry	(context->getTestContext().getArchive(), "vulkan/prebuilt");
+
+		log << err << tcu::TestLog::Message << "Building from source not supported, loading stored binary instead" << tcu::TestLog::EndMessage;
+
+		binProg = de::MovePtr<vk::ProgramBinary>(registry.loadProgram(progId));
+
+		log << iter.getProgram();
+	}
+	catch (const tcu::Exception&)
+	{
+		// Build failed for other reason
+		log << buildInfo;
+		throw;
+	}
+
+	TCU_CHECK_INTERNAL(binProg);
+
+	vk::ProgramBinary* returnBinary = binProg.get();
+
+	progCollection->add(progId.programName, binProg);
+
+	return returnBinary;
+}
+
+} // anonymous(compilation)
+
+namespace vkt
+{
+
+using std::vector;
+using de::UniquePtr;
+using de::MovePtr;
+using tcu::TestLog;
+
+// TestCaseExecutor
+
+class TestCaseExecutor : public tcu::TestCaseExecutor
+{
+public:
+											TestCaseExecutor	(tcu::TestContext& testCtx);
+											~TestCaseExecutor	(void);
+
+	virtual void							init				(tcu::TestCase* testCase, const std::string& path);
+	virtual void							deinit				(tcu::TestCase* testCase);
+
+	virtual tcu::TestNode::IterateResult	iterate				(tcu::TestCase* testCase);
+
+private:
+	vk::BinaryCollection					m_progCollection;
+	de::UniquePtr<vk::Library>				m_library;
+	Context									m_context;
+
+	TestInstance*							m_instance;			//!< Current test case instance
+};
+
+static MovePtr<vk::Library> createLibrary (tcu::TestContext& testCtx)
+{
+	return MovePtr<vk::Library>(testCtx.getPlatform().getVulkanPlatform().createLibrary());
+}
+
+TestCaseExecutor::TestCaseExecutor (tcu::TestContext& testCtx)
+	: m_library		(createLibrary(testCtx))
+	, m_context		(testCtx, m_library->getPlatformInterface(), m_progCollection)
+	, m_instance	(DE_NULL)
+{
+}
+
+TestCaseExecutor::~TestCaseExecutor (void)
+{
+	delete m_instance;
+}
+
+void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePath)
+{
+	const TestCase*			vktCase		= dynamic_cast<TestCase*>(testCase);
+	tcu::TestLog&			log			= m_context.getTestContext().getLog();
+	vk::SourceCollections	sourceProgs;
+
+	DE_UNREF(casePath); // \todo [2015-03-13 pyry] Use this to identify ProgramCollection storage path
+
+	if (!vktCase)
+		TCU_THROW(InternalError, "Test node not an instance of vkt::TestCase");
+
+	m_progCollection.clear();
+	vktCase->initPrograms(sourceProgs);
+
+	for (vk::GlslSourceCollection::Iterator progIter = sourceProgs.glslSources.begin(); progIter != sourceProgs.glslSources.end(); ++progIter)
+	{
+		vk::ProgramBinary* binProg = buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, progIter, &m_context, &m_progCollection);
+
+		try
+		{
+			std::ostringstream disasm;
+
+			vk::disassembleSpirV(binProg->getSize(), binProg->getBinary(), &disasm);
+
+			log << TestLog::KernelSource(disasm.str());
+		}
+		catch (const tcu::NotSupportedError& err)
+		{
+			log << err;
+		}
+	}
+
+	for (vk::SpirVAsmCollection::Iterator asmIterator = sourceProgs.spirvAsmSources.begin(); asmIterator != sourceProgs.spirvAsmSources.end(); ++asmIterator)
+	{
+		buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, &m_context, &m_progCollection);
+	}
+
+	DE_ASSERT(!m_instance);
+	m_instance = vktCase->createInstance(m_context);
+}
+
+void TestCaseExecutor::deinit (tcu::TestCase*)
+{
+	delete m_instance;
+	m_instance = DE_NULL;
+}
+
+tcu::TestNode::IterateResult TestCaseExecutor::iterate (tcu::TestCase*)
+{
+	DE_ASSERT(m_instance);
+
+	const tcu::TestStatus	result	= m_instance->iterate();
+
+	if (result.isComplete())
+	{
+		// Vulkan tests shouldn't set result directly
+		DE_ASSERT(m_context.getTestContext().getTestResult() == QP_TEST_RESULT_LAST);
+		m_context.getTestContext().setTestResult(result.getCode(), result.getDescription().c_str());
+		return tcu::TestNode::STOP;
+	}
+	else
+		return tcu::TestNode::CONTINUE;
+}
+
+// ShaderLibrary-based GLSL tests
+
+class GlslGroup : public tcu::TestCaseGroup
+{
+public:
+	GlslGroup (tcu::TestContext& testCtx)
+		: tcu::TestCaseGroup(testCtx, "glsl", "GLSL shader execution tests")
+	{
+	}
+
+	void init (void)
+	{
+		static const struct
+		{
+			const char*		name;
+			const char*		description;
+		} s_es310Tests[] =
+		{
+			{ "arrays",						"Arrays"					},
+			{ "conditionals",				"Conditional statements"	},
+			{ "constant_expressions",		"Constant expressions"		},
+			{ "constants",					"Constants"					},
+			{ "conversions",				"Type conversions"			},
+			{ "functions",					"Functions"					},
+			{ "linkage",					"Linking"					},
+			{ "scoping",					"Scoping"					},
+			{ "swizzles",					"Swizzles"					},
+		};
+
+		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_es310Tests); ndx++)
+			addChild(createShaderLibraryGroup(m_testCtx,
+											  s_es310Tests[ndx].name,
+											  s_es310Tests[ndx].description,
+											  std::string("vulkan/glsl/es310/") + s_es310Tests[ndx].name + ".test").release());
+	}
+};
+
+// TestPackage
+
+TestPackage::TestPackage (tcu::TestContext& testCtx)
+	: tcu::TestPackage(testCtx, "dEQP-VK", "dEQP Vulkan Tests")
+{
+}
+
+TestPackage::~TestPackage (void)
+{
+}
+
+tcu::TestCaseExecutor* TestPackage::createExecutor (void) const
+{
+	return new TestCaseExecutor(m_testCtx);
+}
+
+void TestPackage::init (void)
+{
+	addChild(createInfoTests			(m_testCtx));
+	addChild(api::createTests			(m_testCtx));
+	addChild(pipeline::createTests		(m_testCtx));
+	addChild(BindingModel::createTests	(m_testCtx));
+	addChild(SpirVAssembly::createTests	(m_testCtx));
+	addChild(new GlslGroup				(m_testCtx));
+	addChild(createRenderPassTests		(m_testCtx));
+}
+
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/vktTestPackage.hpp b/external/vulkancts/modules/vulkan/vktTestPackage.hpp
new file mode 100644
index 0000000..f50ab91
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestPackage.hpp
@@ -0,0 +1,57 @@
+#ifndef _VKTTESTPACKAGE_HPP
+#define _VKTTESTPACKAGE_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan Test Package
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestPackage.hpp"
+#include "tcuResource.hpp"
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+
+class TestPackage : public tcu::TestPackage
+{
+public:
+								TestPackage			(tcu::TestContext& testCtx);
+	virtual						~TestPackage		(void);
+
+	virtual void				init				(void);
+	tcu::TestCaseExecutor*		createExecutor		(void) const;
+};
+
+} // vkt
+
+#endif // _VKTTESTPACKAGE_HPP
diff --git a/external/vulkancts/modules/vulkan/vktTestPackageEntry.cpp b/external/vulkancts/modules/vulkan/vktTestPackageEntry.cpp
new file mode 100644
index 0000000..6b377e7
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vktTestPackageEntry.cpp
@@ -0,0 +1,44 @@
+/*-------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan Test Package Entry Point.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestPackage.hpp"
+
+// Register package to test executor.
+
+static tcu::TestPackage* createTestPackage (tcu::TestContext& testCtx)
+{
+	return new vkt::TestPackage(testCtx);
+}
+
+tcu::TestPackageDescriptor g_vktPackageDescriptor("dEQP-VK", createTestPackage);
diff --git a/external/vulkancts/modules/vulkan/vulkan.cmake b/external/vulkancts/modules/vulkan/vulkan.cmake
new file mode 100644
index 0000000..2b785b0
--- /dev/null
+++ b/external/vulkancts/modules/vulkan/vulkan.cmake
@@ -0,0 +1 @@
+add_subdirectory(vulkan)
diff --git a/framework/common/tcuCommandLine.cpp b/framework/common/tcuCommandLine.cpp
index c660e63..2b96377 100644
--- a/framework/common/tcuCommandLine.cpp
+++ b/framework/common/tcuCommandLine.cpp
@@ -82,6 +82,7 @@
 DE_DECLARE_COMMAND_LINE_OPT(EGLPixmapType,				std::string);
 DE_DECLARE_COMMAND_LINE_OPT(LogImages,					bool);
 DE_DECLARE_COMMAND_LINE_OPT(TestOOM,					bool);
+DE_DECLARE_COMMAND_LINE_OPT(VKDeviceID,					int);
 
 static void parseIntList (const char* src, std::vector<int>* dst)
 {
@@ -163,6 +164,7 @@
 		<< Option<EGLDisplayType>		(DE_NULL,	"deqp-egl-display-type",		"EGL native display type")
 		<< Option<EGLWindowType>		(DE_NULL,	"deqp-egl-window-type",			"EGL native window type")
 		<< Option<EGLPixmapType>		(DE_NULL,	"deqp-egl-pixmap-type",			"EGL native pixmap type")
+		<< Option<VKDeviceID>			(DE_NULL,	"deqp-vk-device-id",			"Vulkan device ID (IDs start from 1)",									"1")
 		<< Option<LogImages>			(DE_NULL,	"deqp-log-images",				"Enable or disable logging of result images",		s_enableNames,		"enable")
 		<< Option<TestOOM>				(DE_NULL,	"deqp-test-oom",				"Run tests that exhaust memory on purpose",			s_enableNames,		TEST_OOM_DEFAULT);
 }
@@ -788,23 +790,24 @@
 	return isOk;
 }
 
-const char*				CommandLine::getLogFileName				(void) const	{ return m_cmdLine.getOption<opt::LogFilename>().c_str();		   }
-deUint32				CommandLine::getLogFlags				(void) const	{ return m_logFlags;											   }
-RunMode					CommandLine::getRunMode					(void) const	{ return m_cmdLine.getOption<opt::RunMode>();					   }
-const char*				CommandLine::getCaseListExportFile		(void) const	{ return m_cmdLine.getOption<opt::ExportFilenamePattern>().c_str();}
-WindowVisibility		CommandLine::getVisibility				(void) const	{ return m_cmdLine.getOption<opt::Visibility>();				   }
-bool					CommandLine::isWatchDogEnabled			(void) const	{ return m_cmdLine.getOption<opt::WatchDog>();					   }
-bool					CommandLine::isCrashHandlingEnabled		(void) const	{ return m_cmdLine.getOption<opt::CrashHandler>();				   }
-int						CommandLine::getBaseSeed				(void) const	{ return m_cmdLine.getOption<opt::BaseSeed>();					   }
-int						CommandLine::getTestIterationCount		(void) const	{ return m_cmdLine.getOption<opt::TestIterationCount>();		   }
-int						CommandLine::getSurfaceWidth			(void) const	{ return m_cmdLine.getOption<opt::SurfaceWidth>();				   }
-int						CommandLine::getSurfaceHeight			(void) const	{ return m_cmdLine.getOption<opt::SurfaceHeight>();				   }
-SurfaceType				CommandLine::getSurfaceType				(void) const	{ return m_cmdLine.getOption<opt::SurfaceType>();				   }
-ScreenRotation			CommandLine::getScreenRotation			(void) const	{ return m_cmdLine.getOption<opt::ScreenRotation>();			   }
-int						CommandLine::getGLConfigId				(void) const	{ return m_cmdLine.getOption<opt::GLConfigID>();				   }
-int						CommandLine::getCLPlatformId			(void) const	{ return m_cmdLine.getOption<opt::CLPlatformID>();				   }
-const std::vector<int>&	CommandLine::getCLDeviceIds				(void) const	{ return m_cmdLine.getOption<opt::CLDeviceIDs>();				   }
-bool					CommandLine::isOutOfMemoryTestEnabled	(void) const	{ return m_cmdLine.getOption<opt::TestOOM>();					   }
+const char*				CommandLine::getLogFileName				(void) const	{ return m_cmdLine.getOption<opt::LogFilename>().c_str();			}
+deUint32				CommandLine::getLogFlags				(void) const	{ return m_logFlags;												}
+RunMode					CommandLine::getRunMode					(void) const	{ return m_cmdLine.getOption<opt::RunMode>();						}
+const char*				CommandLine::getCaseListExportFile		(void) const	{ return m_cmdLine.getOption<opt::ExportFilenamePattern>().c_str();	}
+WindowVisibility		CommandLine::getVisibility				(void) const	{ return m_cmdLine.getOption<opt::Visibility>();					}
+bool					CommandLine::isWatchDogEnabled			(void) const	{ return m_cmdLine.getOption<opt::WatchDog>();						}
+bool					CommandLine::isCrashHandlingEnabled		(void) const	{ return m_cmdLine.getOption<opt::CrashHandler>();					}
+int						CommandLine::getBaseSeed				(void) const	{ return m_cmdLine.getOption<opt::BaseSeed>();						}
+int						CommandLine::getTestIterationCount		(void) const	{ return m_cmdLine.getOption<opt::TestIterationCount>();			}
+int						CommandLine::getSurfaceWidth			(void) const	{ return m_cmdLine.getOption<opt::SurfaceWidth>();					}
+int						CommandLine::getSurfaceHeight			(void) const	{ return m_cmdLine.getOption<opt::SurfaceHeight>();					}
+SurfaceType				CommandLine::getSurfaceType				(void) const	{ return m_cmdLine.getOption<opt::SurfaceType>();					}
+ScreenRotation			CommandLine::getScreenRotation			(void) const	{ return m_cmdLine.getOption<opt::ScreenRotation>();				}
+int						CommandLine::getGLConfigId				(void) const	{ return m_cmdLine.getOption<opt::GLConfigID>();					}
+int						CommandLine::getCLPlatformId			(void) const	{ return m_cmdLine.getOption<opt::CLPlatformID>();					}
+const std::vector<int>&	CommandLine::getCLDeviceIds				(void) const	{ return m_cmdLine.getOption<opt::CLDeviceIDs>();					}
+int						CommandLine::getVKDeviceId				(void) const	{ return m_cmdLine.getOption<opt::VKDeviceID>();					}
+bool					CommandLine::isOutOfMemoryTestEnabled	(void) const	{ return m_cmdLine.getOption<opt::TestOOM>();						}
 
 const char* CommandLine::getGLContextType (void) const
 {
diff --git a/framework/common/tcuCommandLine.hpp b/framework/common/tcuCommandLine.hpp
index 37a79a7..6195bec 100644
--- a/framework/common/tcuCommandLine.hpp
+++ b/framework/common/tcuCommandLine.hpp
@@ -176,6 +176,9 @@
 	//! Get EGL native pixmap factory (--deqp-egl-pixmap-type)
 	const char*						getEGLPixmapType			(void) const;
 
+	//! Get Vulkan device ID (--deqp-vk-device-id)
+	int								getVKDeviceId				(void) const;
+
 	//! Should we run tests that exhaust memory (--deqp-test-oom)
 	bool							isOutOfMemoryTestEnabled(void) const;
 
diff --git a/framework/common/tcuPlatform.cpp b/framework/common/tcuPlatform.cpp
index 271cdcf..2c9344c 100644
--- a/framework/common/tcuPlatform.cpp
+++ b/framework/common/tcuPlatform.cpp
@@ -41,12 +41,17 @@
 
 const glu::Platform& Platform::getGLPlatform (void) const
 {
-	throw tcu::NotSupportedError("OpenGL (ES) is not supported", DE_NULL, __FILE__, __LINE__);
+	TCU_THROW(NotSupportedError, "OpenGL (ES) is not supported");
 }
 
 const eglu::Platform& Platform::getEGLPlatform (void) const
 {
-	throw tcu::NotSupportedError("EGL is not supported", DE_NULL, __FILE__, __LINE__);
+	TCU_THROW(NotSupportedError, "EGL is not supported");
+}
+
+const vk::Platform& Platform::getVulkanPlatform (void) const
+{
+	TCU_THROW(NotSupportedError, "Vulkan is not supported");
 }
 
 } // tcu
diff --git a/framework/common/tcuPlatform.hpp b/framework/common/tcuPlatform.hpp
index 597cb7d..082cf08 100644
--- a/framework/common/tcuPlatform.hpp
+++ b/framework/common/tcuPlatform.hpp
@@ -35,6 +35,11 @@
 class Platform;
 }
 
+namespace vk
+{
+class Platform;
+}
+
 namespace tcu
 {
 
@@ -105,6 +110,8 @@
 	 * \return Reference to EGL platform interface.
 	 *//*--------------------------------------------------------------------*/
 	virtual const eglu::Platform&	getEGLPlatform		(void) const;
+
+	virtual const vk::Platform&		getVulkanPlatform	(void) const;
 };
 
 } // tcu
diff --git a/framework/platform/CMakeLists.txt b/framework/platform/CMakeLists.txt
index f1ff95b..0bbc1f6 100644
--- a/framework/platform/CMakeLists.txt
+++ b/framework/platform/CMakeLists.txt
@@ -98,6 +98,10 @@
 endif ()
 
 add_library(tcutil-platform STATIC ${TCUTIL_PLATFORM_SRCS})
+
+# Add vkutil to the deps before tcutil so that it picks up the c++11 dependencies
+target_link_libraries(tcutil-platform vkutil)
+
 target_link_libraries(tcutil-platform tcutil ${TCUTIL_PLATFORM_LIBS})
 
 # Always link to glutil as some platforms such as Win32 always support GL
diff --git a/framework/platform/X11/tcuX11Platform.cpp b/framework/platform/X11/tcuX11Platform.cpp
index e3f9257..e10db47 100644
--- a/framework/platform/X11/tcuX11Platform.cpp
+++ b/framework/platform/X11/tcuX11Platform.cpp
@@ -25,7 +25,9 @@
 
 #include "deUniquePtr.hpp"
 #include "gluPlatform.hpp"
+#include "vkPlatform.hpp"
 #include "tcuX11.hpp"
+#include "tcuFunctionLibrary.hpp"
 
 #if defined (DEQP_SUPPORT_GLX)
 #	include "tcuX11GlxPlatform.hpp"
@@ -49,23 +51,54 @@
 	}
 };
 
+class VulkanLibrary : public vk::Library
+{
+public:
+	VulkanLibrary (void)
+		: m_library	("libvulkan.so")
+		, m_driver	(m_library)
+	{
+	}
+
+	const vk::PlatformInterface& getPlatformInterface (void) const
+	{
+		return m_driver;
+	}
+
+private:
+	const tcu::DynamicFunctionLibrary	m_library;
+	const vk::PlatformDriver			m_driver;
+};
+
+class X11VulkanPlatform : public vk::Platform
+{
+public:
+	vk::Library* createLibrary (void) const
+	{
+		return new VulkanLibrary();
+	}
+};
+
 class X11Platform : public tcu::Platform
 {
 public:
-							X11Platform		(void);
-	bool					processEvents	(void) { return !m_eventState.getQuitFlag(); }
-	const glu::Platform&	getGLPlatform	(void) const { return m_glPlatform; }
+							X11Platform			(void);
+	bool					processEvents		(void) { return !m_eventState.getQuitFlag(); }
+	const glu::Platform&	getGLPlatform		(void) const { return m_glPlatform; }
 
 #if defined (DEQP_SUPPORT_EGL)
-	const eglu::Platform&	getEGLPlatform	(void) const { return m_eglPlatform; }
+	const eglu::Platform&	getEGLPlatform		(void) const { return m_eglPlatform; }
 #endif // DEQP_SUPPORT_EGL
 
+	const vk::Platform&		getVulkanPlatform	(void) const { return m_vkPlatform; }
+
 private:
 	EventState				m_eventState;
 #if defined (DEQP_SUPPORT_EGL)
 	x11::egl::Platform		m_eglPlatform;
 #endif // DEQP_SPPORT_EGL
 	X11GLPlatform			m_glPlatform;
+	X11VulkanPlatform		m_vkPlatform;
 };
 
 X11Platform::X11Platform (void)
diff --git a/framework/platform/android/tcuAndroidPlatform.cpp b/framework/platform/android/tcuAndroidPlatform.cpp
index eca3fe0..d9a46d5 100644
--- a/framework/platform/android/tcuAndroidPlatform.cpp
+++ b/framework/platform/android/tcuAndroidPlatform.cpp
@@ -29,6 +29,7 @@
 #include "egluUtil.hpp"
 #include "eglwLibrary.hpp"
 #include "eglwEnums.hpp"
+#include "tcuFunctionLibrary.hpp"
 
 // Assume no call translation is needed
 #include <android/native_window.h>
@@ -183,6 +184,27 @@
 	return new NativeDisplay();
 }
 
+// Vulkan
+
+class VulkanLibrary : public vk::Library
+{
+public:
+	VulkanLibrary (void)
+		: m_library	("libvulkan.so")
+		, m_driver	(m_library)
+	{
+	}
+
+	const vk::PlatformInterface& getPlatformInterface (void) const
+	{
+		return m_driver;
+	}
+
+private:
+	const tcu::DynamicFunctionLibrary	m_library;
+	const vk::PlatformDriver			m_driver;
+};
+
 // Platform
 
 Platform::Platform (void)
@@ -201,5 +223,10 @@
 	return true;
 }
 
+vk::Library* Platform::createLibrary (void) const
+{
+	return new VulkanLibrary();
+}
+
 } // Android
 } // tcu
diff --git a/framework/platform/android/tcuAndroidPlatform.hpp b/framework/platform/android/tcuAndroidPlatform.hpp
index d8463c3..45406a6 100644
--- a/framework/platform/android/tcuAndroidPlatform.hpp
+++ b/framework/platform/android/tcuAndroidPlatform.hpp
@@ -27,6 +27,7 @@
 #include "tcuPlatform.hpp"
 #include "egluPlatform.hpp"
 #include "gluPlatform.hpp"
+#include "vkPlatform.hpp"
 #include "tcuAndroidWindow.hpp"
 
 namespace tcu
@@ -34,7 +35,7 @@
 namespace Android
 {
 
-class Platform : public tcu::Platform, private eglu::Platform, private glu::Platform
+class Platform : public tcu::Platform, private eglu::Platform, private glu::Platform, private vk::Platform
 {
 public:
 									Platform			(void);
@@ -44,9 +45,12 @@
 
 	virtual const glu::Platform&	getGLPlatform		(void) const { return static_cast<const glu::Platform&>(*this);		}
 	virtual const eglu::Platform&	getEGLPlatform		(void) const { return static_cast<const eglu::Platform&>(*this);	}
+	virtual const vk::Platform&		getVulkanPlatform	(void) const { return static_cast<const vk::Platform&>(*this);		}
 
 	WindowRegistry&					getWindowRegistry	(void) { return m_windowRegistry; }
 
+	vk::Library*					createLibrary		(void) const;
+
 private:
 	WindowRegistry					m_windowRegistry;
 };
diff --git a/framework/platform/null/tcuNullPlatform.cpp b/framework/platform/null/tcuNullPlatform.cpp
index ea790e5..e0721ec 100644
--- a/framework/platform/null/tcuNullPlatform.cpp
+++ b/framework/platform/null/tcuNullPlatform.cpp
@@ -26,6 +26,7 @@
 #include "tcuNullRenderContext.hpp"
 #include "egluNativeDisplay.hpp"
 #include "eglwLibrary.hpp"
+#include "vkNullDriver.hpp"
 
 namespace tcu
 {
@@ -74,6 +75,11 @@
 {
 }
 
+vk::Library* Platform::createLibrary (void) const
+{
+	return vk::createNullDriver();
+}
+
 } // null
 } // tcu
 
diff --git a/framework/platform/null/tcuNullPlatform.hpp b/framework/platform/null/tcuNullPlatform.hpp
index 81ff514..612edf2 100644
--- a/framework/platform/null/tcuNullPlatform.hpp
+++ b/framework/platform/null/tcuNullPlatform.hpp
@@ -27,20 +27,26 @@
 #include "tcuPlatform.hpp"
 #include "gluPlatform.hpp"
 #include "egluPlatform.hpp"
+#include "vkPlatform.hpp"
 
 namespace tcu
 {
 namespace null
 {
 
-class Platform : public tcu::Platform, private glu::Platform, private eglu::Platform
+class Platform : public tcu::Platform, private glu::Platform, private eglu::Platform, private vk::Platform
 {
 public:
-									Platform		(void);
-	virtual							~Platform		(void);
+									Platform			(void);
+	virtual							~Platform			(void);
 
-	virtual const glu::Platform&	getGLPlatform	(void) const { return static_cast<const glu::Platform&>(*this); }
-	virtual const eglu::Platform&	getEGLPlatform	(void) const { return static_cast<const eglu::Platform&>(*this); }
+	virtual const glu::Platform&	getGLPlatform		(void) const { return static_cast<const glu::Platform&>(*this); }
+	virtual const eglu::Platform&	getEGLPlatform		(void) const { return static_cast<const eglu::Platform&>(*this); }
+	virtual const vk::Platform&		getVulkanPlatform	(void) const { return static_cast<const vk::Platform&>(*this);	}
+
+private:
+	virtual vk::Library*			createLibrary		(void) const;
+
 };
 
 } // null
diff --git a/framework/platform/win32/tcuWin32Platform.cpp b/framework/platform/win32/tcuWin32Platform.cpp
index dc509a5..4f36535 100644
--- a/framework/platform/win32/tcuWin32Platform.cpp
+++ b/framework/platform/win32/tcuWin32Platform.cpp
@@ -23,6 +23,7 @@
 
 #include "tcuWin32Platform.hpp"
 #include "tcuWGLContextFactory.hpp"
+#include "tcuFunctionLibrary.hpp"
 
 #if defined(DEQP_SUPPORT_EGL)
 #	include "tcuWin32EGLNativeDisplayFactory.hpp"
@@ -32,6 +33,25 @@
 namespace tcu
 {
 
+class VulkanLibrary : public vk::Library
+{
+public:
+	VulkanLibrary (void)
+		: m_library	("vulkan.dll")
+		, m_driver	(m_library)
+	{
+	}
+
+	const vk::PlatformInterface& getPlatformInterface (void) const
+	{
+		return m_driver;
+	}
+
+private:
+	const tcu::DynamicFunctionLibrary	m_library;
+	const vk::PlatformDriver			m_driver;
+};
+
 Win32Platform::Win32Platform (void)
 	: m_instance(GetModuleHandle(NULL))
 {
@@ -86,6 +106,11 @@
 	return true;
 }
 
+vk::Library* Win32Platform::createLibrary (void) const
+{
+	return new VulkanLibrary();
+}
+
 } // tcu
 
 // Create platform
diff --git a/framework/platform/win32/tcuWin32Platform.hpp b/framework/platform/win32/tcuWin32Platform.hpp
index b8f2437..8fc172b 100644
--- a/framework/platform/win32/tcuWin32Platform.hpp
+++ b/framework/platform/win32/tcuWin32Platform.hpp
@@ -26,6 +26,7 @@
 #include "tcuDefs.hpp"
 #include "tcuPlatform.hpp"
 #include "gluPlatform.hpp"
+#include "vkPlatform.hpp"
 #include "tcuWin32API.h"
 
 #if defined(DEQP_SUPPORT_EGL)
@@ -37,7 +38,7 @@
 namespace tcu
 {
 
-class Win32Platform : public tcu::Platform, private glu::Platform
+class Win32Platform : public tcu::Platform, private glu::Platform, private vk::Platform
 #if defined(DEQP_SUPPORT_EGL)
 	, private eglu::Platform
 #endif
@@ -54,7 +55,11 @@
 	const eglu::Platform&	getEGLPlatform		(void) const { return static_cast<const eglu::Platform&>(*this);	}
 #endif
 
+	const vk::Platform&		getVulkanPlatform	(void) const { return static_cast<const vk::Platform&>(*this);		}
+
 private:
+	vk::Library*			createLibrary		(void) const;
+
 	HINSTANCE				m_instance;
 };
 
diff --git a/framework/referencerenderer/rrFragmentOperations.cpp b/framework/referencerenderer/rrFragmentOperations.cpp
index 6d0f1f9..d0fb3c3 100644
--- a/framework/referencerenderer/rrFragmentOperations.cpp
+++ b/framework/referencerenderer/rrFragmentOperations.cpp
@@ -24,6 +24,7 @@
 #include "rrFragmentOperations.hpp"
 #include "tcuVectorUtil.hpp"
 #include "tcuTextureUtil.hpp"
+#include <limits>
 
 using tcu::IVec2;
 using tcu::Vec3;
@@ -303,20 +304,20 @@
 
 void FragmentProcessor::executeBlendFactorComputeRGB (const Vec4& blendColor, const BlendState& blendRGBState)
 {
-#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)											\
-	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)								\
-	{																											\
-		if (m_sampleRegister[regSampleNdx].isAlive)																\
-		{																										\
-			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;							\
-			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;							\
-			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;							\
-			DE_UNREF(src);																						\
-			DE_UNREF(src1);																						\
-			DE_UNREF(dst);																						\
-																												\
-			m_sampleRegister[regSampleNdx].FACTOR_NAME = clamp((FACTOR_EXPRESSION), Vec3(0.0f), Vec3(1.0f));	\
-		}																										\
+#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)																				\
+	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)																	\
+	{																																				\
+		if (m_sampleRegister[regSampleNdx].isAlive)																									\
+		{																																			\
+			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;																\
+			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;																\
+			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;																\
+			DE_UNREF(src);																															\
+			DE_UNREF(src1);																															\
+			DE_UNREF(dst);																															\
+																																					\
+			m_sampleRegister[regSampleNdx].FACTOR_NAME = (FACTOR_EXPRESSION);																		\
+		}																																			\
 	}
 
 #define SWITCH_SRC_OR_DST_FACTOR_RGB(FUNC_NAME, FACTOR_NAME)																					\
@@ -354,20 +355,20 @@
 
 void FragmentProcessor::executeBlendFactorComputeA (const Vec4& blendColor, const BlendState& blendAState)
 {
-#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)								\
-	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)					\
-	{																								\
-		if (m_sampleRegister[regSampleNdx].isAlive)													\
-		{																							\
-			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;				\
-			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;				\
-			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;				\
-			DE_UNREF(src);																			\
-			DE_UNREF(src1);																			\
-			DE_UNREF(dst);																			\
-																									\
-			m_sampleRegister[regSampleNdx].FACTOR_NAME = clamp((FACTOR_EXPRESSION), 0.0f, 1.0f);	\
-		}																							\
+#define SAMPLE_REGISTER_BLEND_FACTOR(FACTOR_NAME, FACTOR_EXPRESSION)														\
+	for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)											\
+	{																														\
+		if (m_sampleRegister[regSampleNdx].isAlive)																			\
+		{																													\
+			const Vec4& src		= m_sampleRegister[regSampleNdx].clampedBlendSrcColor;										\
+			const Vec4& src1	= m_sampleRegister[regSampleNdx].clampedBlendSrc1Color;										\
+			const Vec4& dst		= m_sampleRegister[regSampleNdx].clampedBlendDstColor;										\
+			DE_UNREF(src);																									\
+			DE_UNREF(src1);																									\
+			DE_UNREF(dst);																									\
+																															\
+			m_sampleRegister[regSampleNdx].FACTOR_NAME = (FACTOR_EXPRESSION);												\
+		}																													\
 	}
 
 #define SWITCH_SRC_OR_DST_FACTOR_A(FUNC_NAME, FACTOR_NAME)																		\
@@ -843,6 +844,28 @@
 		switch (fragmentDataType)
 		{
 			case rr::GENERICVECTYPE_FLOAT:
+			{
+				// Select min/max clamping values for blending factors and operands
+				Vec4 minClampValue;
+				Vec4 maxClampValue;
+
+				if (colorbufferClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
+				{
+					minClampValue = Vec4(0.0f);
+					maxClampValue = Vec4(1.0f);
+				}
+				else if (colorbufferClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT)
+				{
+					minClampValue = Vec4(-1.0f);
+					maxClampValue = Vec4(1.0f);
+				}
+				else
+				{
+					// No clamping
+					minClampValue = Vec4(-std::numeric_limits<float>::infinity());
+					maxClampValue = Vec4(std::numeric_limits<float>::infinity());
+				}
+
 				// Blend calculation - only if using blend.
 				if (state.blendMode == BLENDMODE_STANDARD)
 				{
@@ -855,9 +878,9 @@
 							const Fragment&		frag			= inputFragments[groupFirstFragNdx + regSampleNdx/numSamplesPerFragment];
 							Vec4				dstColor		= colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
 
-							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= clamp(frag.value.get<float>(), Vec4(0.0f), Vec4(1.0f));
-							m_sampleRegister[regSampleNdx].clampedBlendSrc1Color	= clamp(frag.value1.get<float>(), Vec4(0.0f), Vec4(1.0f));
-							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, Vec4(0.0f), Vec4(1.0f));
+							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= clamp(frag.value.get<float>(), minClampValue, maxClampValue);
+							m_sampleRegister[regSampleNdx].clampedBlendSrc1Color	= clamp(frag.value1.get<float>(), minClampValue, maxClampValue);
+							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, minClampValue, maxClampValue);
 						}
 					}
 
@@ -881,8 +904,8 @@
 							const Vec4			srcColor		= frag.value.get<float>();
 							const Vec4			dstColor		= colorBuffer.getPixel(fragSampleNdx, frag.pixelCoord.x(), frag.pixelCoord.y());
 
-							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= unpremultiply(clamp(srcColor, Vec4(0.0f), Vec4(1.0f)));
-							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= unpremultiply(clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, Vec4(0.0f), Vec4(1.0f)));
+							m_sampleRegister[regSampleNdx].clampedBlendSrcColor		= unpremultiply(clamp(srcColor, minClampValue, maxClampValue));
+							m_sampleRegister[regSampleNdx].clampedBlendDstColor		= unpremultiply(clamp(sRGBTarget ? tcu::sRGBToLinear(dstColor) : dstColor, minClampValue, maxClampValue));
 						}
 					}
 
@@ -905,6 +928,19 @@
 					}
 				}
 
+				// Clamp result values in sample register
+				if (colorbufferClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
+				{
+					for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
+					{
+						if (m_sampleRegister[regSampleNdx].isAlive)
+						{
+							m_sampleRegister[regSampleNdx].blendedRGB	= clamp(m_sampleRegister[regSampleNdx].blendedRGB, minClampValue.swizzle(0, 1, 2), maxClampValue.swizzle(0, 1, 2));
+							m_sampleRegister[regSampleNdx].blendedA		= clamp(m_sampleRegister[regSampleNdx].blendedA, minClampValue.w(), maxClampValue.w());
+						}
+					}
+				}
+
 				// Finally, write the colors to the color buffer.
 
 				if (state.colorMask[0] && state.colorMask[1] && state.colorMask[2] && state.colorMask[3])
@@ -917,7 +953,7 @@
 				else if (state.colorMask[0] || state.colorMask[1] || state.colorMask[2] || state.colorMask[3])
 					executeMaskedColorWrite(groupFirstFragNdx, numSamplesPerFragment, inputFragments, colorMaskFactor, colorMaskNegationFactor, sRGBTarget, colorBuffer);
 				break;
-
+			}
 			case rr::GENERICVECTYPE_INT32:
 				// Write fragments
 				for (int regSampleNdx = 0; regSampleNdx < SAMPLE_REGISTER_SIZE; regSampleNdx++)
diff --git a/modules/internal/CMakeLists.txt b/modules/internal/CMakeLists.txt
index 2db2b50..6e258d4 100644
--- a/modules/internal/CMakeLists.txt
+++ b/modules/internal/CMakeLists.txt
@@ -23,11 +23,14 @@
 	ditSRGB8ConversionTest.cpp
 	ditTextureFormatTests.cpp
 	ditTextureFormatTests.hpp
+	ditVulkanTests.cpp
+	ditVulkanTests.hpp
 	)
 
 set(DE_INTERNAL_TESTS_LIBS
 	tcutil
 	referencerenderer
+	vkutil
 	)
 
 add_deqp_module(de-internal-tests "${DE_INTERNAL_TESTS_SRCS}" "${DE_INTERNAL_TESTS_LIBS}" ditTestPackageEntry.cpp)
diff --git a/modules/internal/ditFrameworkTests.cpp b/modules/internal/ditFrameworkTests.cpp
index 8725240..7f54800 100644
--- a/modules/internal/ditFrameworkTests.cpp
+++ b/modules/internal/ditFrameworkTests.cpp
@@ -23,6 +23,8 @@
 
 #include "ditFrameworkTests.hpp"
 #include "ditTextureFormatTests.hpp"
+#include "ditVulkanTests.hpp"
+
 #include "tcuFloatFormat.hpp"
 #include "tcuEither.hpp"
 #include "tcuTestLog.hpp"
@@ -911,6 +913,7 @@
 	addChild(new CaseListParserTests	(m_testCtx));
 	addChild(new ReferenceRendererTests	(m_testCtx));
 	addChild(createTextureFormatTests	(m_testCtx));
+	addChild(createVulkanTests			(m_testCtx));
 }
 
 } // dit
diff --git a/modules/internal/ditVulkanTests.cpp b/modules/internal/ditVulkanTests.cpp
new file mode 100644
index 0000000..28c416b
--- /dev/null
+++ b/modules/internal/ditVulkanTests.cpp
@@ -0,0 +1,43 @@
+/*-------------------------------------------------------------------------
+ * drawElements Internal Test Module
+ * ---------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan framework tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "ditVulkanTests.hpp"
+#include "ditTestCase.hpp"
+
+#include "vkImageUtil.hpp"
+
+#include "deUniquePtr.hpp"
+
+namespace dit
+{
+
+tcu::TestCaseGroup* createVulkanTests (tcu::TestContext& testCtx)
+{
+	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "vulkan", "Vulkan Framework Tests"));
+
+	group->addChild(new SelfCheckCase(testCtx, "image_util", "ImageUtil self-check tests", vk::imageUtilSelfTest));
+
+	return group.release();
+}
+
+} // dit
diff --git a/modules/internal/ditVulkanTests.hpp b/modules/internal/ditVulkanTests.hpp
new file mode 100644
index 0000000..6f1a05c
--- /dev/null
+++ b/modules/internal/ditVulkanTests.hpp
@@ -0,0 +1,36 @@
+#ifndef _DITVULKANTESTS_HPP
+#define _DITVULKANTESTS_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Internal Test Module
+ * ---------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan framework tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace dit
+{
+
+tcu::TestCaseGroup*	createVulkanTests	(tcu::TestContext& testCtx);
+
+} // dit
+
+#endif // _DITVULKANTESTS_HPP
diff --git a/scripts/build_caselists.py b/scripts/build_caselists.py
index ec9ea01..329eaaa 100644
--- a/scripts/build_caselists.py
+++ b/scripts/build_caselists.py
@@ -38,11 +38,12 @@
 		self.binName	= binName
 
 MODULES = [
-	Module("dE-IT",			"internal",		"de-internal-tests"),
-	Module("dEQP-EGL",		"egl",			"deqp-egl"),
-	Module("dEQP-GLES2",	"gles2",		"deqp-gles2"),
-	Module("dEQP-GLES3",	"gles3",		"deqp-gles3"),
-	Module("dEQP-GLES31",	"gles31",		"deqp-gles31"),
+	Module("dE-IT",			"internal",								"de-internal-tests"),
+	Module("dEQP-EGL",		"egl",									"deqp-egl"),
+	Module("dEQP-GLES2",	"gles2",								"deqp-gles2"),
+	Module("dEQP-GLES3",	"gles3",								"deqp-gles3"),
+	Module("dEQP-GLES31",	"gles31",								"deqp-gles31"),
+	Module("dEQP-VK",		"../external/vulkancts/modules/vulkan",	"deqp-vk"),
 ]
 
 DEFAULT_BUILD_DIR	= os.path.join(tempfile.gettempdir(), "deqp-caselists", "{targetName}-{buildType}")