Merge changes I87bf1147,I1bfc5656 into nyc-dev
authorMika Isojarvi <misojarvi@google.com>
Mon, 21 Mar 2016 21:03:15 +0000 (21:03 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Mon, 21 Mar 2016 21:03:15 +0000 (21:03 +0000)
* changes:
  Enable blending for floating point formats
  Always disable blending for 32bit float formats

17 files changed:
android/cts/master/com.drawelements.deqp.vk.xml
android/cts/master/vk-master.txt
external/vulkancts/README.md
external/vulkancts/framework/vulkan/vkDeviceUtil.cpp
external/vulkancts/framework/vulkan/vkDeviceUtil.hpp
external/vulkancts/modules/vulkan/api/vktApiBufferTests.cpp
external/vulkancts/modules/vulkan/memory/vktMemoryPipelineBarrierTests.cpp
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmInstructionTests.cpp
external/vulkancts/modules/vulkan/vktSynchronization.cpp
external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp
framework/common/tcuCommandLine.cpp
framework/common/tcuTestHierarchyUtil.cpp
framework/qphelper/qpTestLog.c
framework/qphelper/qpTestLog.h
framework/qphelper/qpXmlWriter.c
framework/qphelper/qpXmlWriter.h

index 6a6cef9..3b93b5d 100644 (file)
                                        <Test name="create">
                                                <TestInstance/>
                                        </Test>
+                                       <Test name="create_custom_allocator">
+                                               <TestInstance/>
+                                       </Test>
+                                       <Test name="create_simulate_oom">
+                                               <TestInstance/>
+                                       </Test>
                                        <Test name="query_support">
                                                <TestInstance/>
                                        </Test>
                                                        <TestInstance/>
                                                </Test>
                                        </TestCase>
+                                       <TestCase name="simulate_oom">
+                                               <Test name="min_image_count">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="image_format">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="image_extent">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="image_array_layers">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="image_usage">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="image_sharing_mode">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="pre_transform">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="composite_alpha">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="present_mode">
+                                                       <TestInstance/>
+                                               </Test>
+                                               <Test name="clipped">
+                                                       <TestInstance/>
+                                               </Test>
+                                       </TestCase>
                                </TestSuite>
                        </TestSuite>
                </TestSuite>
index 67729e3..fdb1556 100644 (file)
@@ -80289,6 +80289,8 @@ dEQP-VK.image.image_size.buffer.readonly_writeonly_12
 dEQP-VK.image.image_size.buffer.readonly_writeonly_1
 dEQP-VK.image.image_size.buffer.readonly_writeonly_7
 dEQP-VK.wsi.android.surface.create
+dEQP-VK.wsi.android.surface.create_custom_allocator
+dEQP-VK.wsi.android.surface.create_simulate_oom
 dEQP-VK.wsi.android.surface.query_support
 dEQP-VK.wsi.android.surface.query_capabilities
 dEQP-VK.wsi.android.surface.query_formats
@@ -80304,6 +80306,16 @@ dEQP-VK.wsi.android.swapchain.create.pre_transform
 dEQP-VK.wsi.android.swapchain.create.composite_alpha
 dEQP-VK.wsi.android.swapchain.create.present_mode
 dEQP-VK.wsi.android.swapchain.create.clipped
+dEQP-VK.wsi.android.swapchain.simulate_oom.min_image_count
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_format
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_extent
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_array_layers
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_usage
+dEQP-VK.wsi.android.swapchain.simulate_oom.image_sharing_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.pre_transform
+dEQP-VK.wsi.android.swapchain.simulate_oom.composite_alpha
+dEQP-VK.wsi.android.swapchain.simulate_oom.present_mode
+dEQP-VK.wsi.android.swapchain.simulate_oom.clipped
 dEQP-VK.synchronization.fences
 dEQP-VK.synchronization.semaphores
 dEQP-VK.synchronization.events
index 65561e9..7985148 100644 (file)
@@ -134,6 +134,11 @@ can be selected with:
 
        --deqp-vk-device-id=<value>
 
+To speed up the conformance run on some platforms the following command line
+option may be used to disable frequent fflush() calls to the output logs:
+
+       --deqp-log-flush=disable
+
 No other command line options are allowed.
 
 ### Win32
index a551680..3e146f6 100644 (file)
@@ -43,9 +43,10 @@ namespace vk
 using std::vector;
 using std::string;
 
-Move<VkInstance> createDefaultInstance (const PlatformInterface&       vkPlatform,
-                                                                               const vector<string>&           enabledLayers,
-                                                                               const vector<string>&           enabledExtensions)
+Move<VkInstance> createDefaultInstance (const PlatformInterface&               vkPlatform,
+                                                                               const vector<string>&                   enabledLayers,
+                                                                               const vector<string>&                   enabledExtensions,
+                                                                               const VkAllocationCallbacks*    pAllocator)
 {
        vector<const char*>             layerNamePtrs           (enabledLayers.size());
        vector<const char*>             extensionNamePtrs       (enabledExtensions.size());
@@ -79,12 +80,12 @@ Move<VkInstance> createDefaultInstance (const PlatformInterface&    vkPlatform,
        for (size_t ndx = 0; ndx < enabledExtensions.size(); ++ndx)
                extensionNamePtrs[ndx] = enabledExtensions[ndx].c_str();
 
-       return createInstance(vkPlatform, &instanceInfo);
+       return createInstance(vkPlatform, &instanceInfo, pAllocator);
 }
 
 Move<VkInstance> createDefaultInstance (const PlatformInterface& vkPlatform)
 {
-       return createDefaultInstance(vkPlatform, vector<string>(), vector<string>());
+       return createDefaultInstance(vkPlatform, vector<string>(), vector<string>(), DE_NULL);
 }
 
 VkPhysicalDevice chooseDevice (const InstanceInterface& vkInstance, VkInstance instance, const tcu::CommandLine& cmdLine)
index 3b59e8b..123a815 100644 (file)
@@ -47,7 +47,8 @@ namespace vk
 Move<VkInstance>       createDefaultInstance   (const PlatformInterface&                       vkPlatform);
 Move<VkInstance>       createDefaultInstance   (const PlatformInterface&                       vkPlatform,
                                                                                         const std::vector<std::string>&        enabledLayers,
-                                                                                        const std::vector<std::string>&        enabledExtensions);
+                                                                                        const std::vector<std::string>&        enabledExtensions,
+                                                                                        const VkAllocationCallbacks*           pAllocator      = DE_NULL);
 
 VkPhysicalDevice       chooseDevice                    (const InstanceInterface&                       vkInstance,
                                                                                         VkInstance                                                     instance,
index 6b36cce..f4dc86e 100644 (file)
@@ -50,6 +50,8 @@ namespace api
 namespace
 {
 
+static const deUint32  MAX_BUFFER_SIZE_DIVISOR = 16;
+
 struct BufferCaseParameters
 {
        VkBufferUsageFlags      usage;
@@ -97,16 +99,19 @@ private:
 
  tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
 {
-       const VkDevice                  vkDevice                        = m_context.getDevice();
-       const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
-       Move<VkBuffer>                  testBuffer;
-       VkMemoryRequirements    memReqs;
-       Move<VkDeviceMemory>    memory;
-       const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       const VkPhysicalDevice          vkPhysicalDevice        = m_context.getPhysicalDevice();
+       const InstanceInterface&        vkInstance                      = m_context.getInstanceInterface();
+       const VkDevice                          vkDevice                        = m_context.getDevice();
+       const DeviceInterface&          vk                                      = m_context.getDeviceInterface();
+       Move<VkBuffer>                          testBuffer;
+       VkMemoryRequirements            memReqs;
+       Move<VkDeviceMemory>            memory;
+       const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       const VkPhysicalDeviceMemoryProperties  memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
 
        // Create buffer
        {
-               const VkBufferCreateInfo                bufferParams            =
+               VkBufferCreateInfo              bufferParams            =
                {
                        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
                        DE_NULL,
@@ -120,7 +125,7 @@ private:
 
                try
                {
-                       testBuffer = createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
+                       testBuffer = createBuffer(vk, vkDevice, &bufferParams);
                }
                catch (const vk::Error& error)
                {
@@ -129,6 +134,27 @@ private:
 
                vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
 
+               const deUint32          heapTypeIndex   = (deUint32)deCtz32(memReqs.memoryTypeBits);
+               const VkMemoryType      memoryType              = memoryProperties.memoryTypes[heapTypeIndex];
+               const VkMemoryHeap      memoryHeap              = memoryProperties.memoryHeaps[memoryType.heapIndex];
+               const VkDeviceSize      maxBufferSize   = memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
+               // If the requested size is too large, clamp it based on the selected heap size
+               if (size > maxBufferSize)
+               {
+                       size = maxBufferSize;
+                       bufferParams.size = size;
+                       try
+                       {
+                               // allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
+                               testBuffer = createBuffer(vk, vkDevice, &bufferParams);
+                       }
+                       catch (const vk::Error& error)
+                       {
+                               return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
+                       }
+                       vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
+               }
+
                if (size > memReqs.size)
                {
                        std::ostringstream errorMsg;
@@ -250,14 +276,10 @@ tcu::TestStatus BufferTestInstance::iterate (void)
        {
                const VkPhysicalDevice                                  vkPhysicalDevice        = m_context.getPhysicalDevice();
                const InstanceInterface&                                vkInstance                      = m_context.getInstanceInterface();
-               const VkPhysicalDeviceMemoryProperties  memoryProperties        = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
                VkPhysicalDeviceProperties      props;
 
                vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
-
-               const VkDeviceSize maxTestBufferSize = de::min((VkDeviceSize) props.limits.maxTexelBufferElements, memoryProperties.memoryHeaps[memoryProperties.memoryTypes[0].heapIndex].size / 16);
-
-               testStatus = bufferCreateAndAllocTest(maxTestBufferSize);
+               testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
        }
 
        return testStatus;
index 68f9396..61cb205 100644 (file)
@@ -60,7 +60,7 @@
 #include <string>
 #include <vector>
 
-// \todo Check bufferImageGranularity
+// \todo [2016-03-09 mika] Check bufferImageGranularity
 
 using tcu::TestLog;
 using tcu::Maybe;
@@ -145,7 +145,7 @@ enum Usage
        USAGE_UNIFORM_TEXEL_BUFFER = (0x1u<<8),
        USAGE_STORAGE_TEXEL_BUFFER = (0x1u<<9),
 
-       // \todo This is probably almost impossible to do
+       // \todo [2016-03-09 mika] This is probably almost impossible to do
        USAGE_INDIRECT_BUFFER = (0x1u<<10),
 
        // Texture usage flags
@@ -753,7 +753,7 @@ void ReferenceMemory::setData (size_t offset, size_t size, const void* data_)
 {
        const deUint8* data = (const deUint8*)data_;
 
-       // \todo Optimize
+       // \todo [2016-03-09 mika] Optimize
        for (size_t pos = 0; pos < size; pos++)
        {
                m_data[offset + pos] = data[pos];
@@ -763,7 +763,7 @@ void ReferenceMemory::setData (size_t offset, size_t size, const void* data_)
 
 void ReferenceMemory::setUndefined     (size_t offset, size_t size)
 {
-       // \todo Optimize
+       // \todo [2016-03-09 mika] Optimize
        for (size_t pos = 0; pos < size; pos++)
                m_defined[(offset + pos) / 64] |= 0x1ull << ((offset + pos) % 64);
 }
@@ -874,7 +874,7 @@ vk::VkDeviceSize roundBufferSizeToWxHx4 (vk::VkDeviceSize size)
        vk::VkDeviceSize                bestW                   = de::max(maxTexelCount, maxTextureSize);
        vk::VkDeviceSize                bestH                   = maxTexelCount / bestW;
 
-       // \todo Could probably be faster?
+       // \todo [2016-03-09 mika] Could probably be faster?
        for (vk::VkDeviceSize w = 1; w * w < maxTexelCount && w < maxTextureSize && bestW * bestH * 4 < size; w++)
        {
                const vk::VkDeviceSize h = maxTexelCount / w;
@@ -898,7 +898,7 @@ IVec2 findImageSizeWxHx4 (vk::VkDeviceSize size)
 
        DE_ASSERT((size % 4) == 0);
 
-       // \todo Could probably be faster?
+       // \todo [2016-03-09 mika] Could probably be faster?
        for (vk::VkDeviceSize w = 1; w < maxTextureSize && w < texelCount; w++)
        {
                const vk::VkDeviceSize  h       = texelCount / w;
@@ -2077,7 +2077,15 @@ void PipelineBarrier::submit (SubmitContext& context)
 class ImageTransition : public CmdCommand
 {
 public:
-                                               ImageTransition         (void) {}
+                                               ImageTransition         (vk::VkPipelineStageFlags       srcStages,
+                                                                                        vk::VkAccessFlags                      srcAccesses,
+
+                                                                                        vk::VkPipelineStageFlags       dstStages,
+                                                                                        vk::VkAccessFlags                      dstAccesses,
+
+                                                                                        vk::VkImageLayout                      srcLayout,
+                                                                                        vk::VkImageLayout                      dstLayout);
+
                                                ~ImageTransition        (void) {}
        const char*                     getName                         (void) const { return "ImageTransition"; }
 
@@ -2087,17 +2095,47 @@ public:
        void                            verify                          (VerifyContext& context, size_t);
 
 private:
-       vk::VkDeviceSize        m_imageMemorySize;
+       const vk::VkPipelineStageFlags  m_srcStages;
+       const vk::VkAccessFlags                 m_srcAccesses;
+       const vk::VkPipelineStageFlags  m_dstStages;
+       const vk::VkAccessFlags                 m_dstAccesses;
+       const vk::VkImageLayout                 m_srcLayout;
+       const vk::VkImageLayout                 m_dstLayout;
+
+       vk::VkDeviceSize                                m_imageMemorySize;
 };
 
+ImageTransition::ImageTransition (vk::VkPipelineStageFlags     srcStages,
+                                                                 vk::VkAccessFlags                     srcAccesses,
+
+                                                                 vk::VkPipelineStageFlags      dstStages,
+                                                                 vk::VkAccessFlags                     dstAccesses,
+
+                                                                 vk::VkImageLayout                     srcLayout,
+                                                                 vk::VkImageLayout                     dstLayout)
+       : m_srcStages           (srcStages)
+       , m_srcAccesses         (srcAccesses)
+       , m_dstStages           (dstStages)
+       , m_dstAccesses         (dstAccesses)
+       , m_srcLayout           (srcLayout)
+       , m_dstLayout           (dstLayout)
+{
+}
+
 void ImageTransition::logSubmit (TestLog& log, size_t commandIndex) const
 {
-       log << TestLog::Message << commandIndex << ":" << getName() << " Use pipeline barrier to transition to VK_IMAGE_LAYOUT_GENERAL." << TestLog::EndMessage;
+       log << TestLog::Message << commandIndex << ":" << getName()
+               << " Image transition pipeline barrier"
+               << ", srcStages: " << vk::getPipelineStageFlagsStr(m_srcStages) << ", srcAccesses: " << vk::getAccessFlagsStr(m_srcAccesses)
+               << ", dstStages: " << vk::getPipelineStageFlagsStr(m_dstStages) << ", dstAccesses: " << vk::getAccessFlagsStr(m_dstAccesses)
+               << ", srcLayout: " << m_srcLayout << ", dstLayout: " << m_dstLayout << TestLog::EndMessage;
 }
 
 void ImageTransition::prepare (PrepareContext& context)
 {
-       context.setImageLayout(vk::VK_IMAGE_LAYOUT_GENERAL);
+       DE_ASSERT(context.getImageLayout() == vk::VK_IMAGE_LAYOUT_UNDEFINED || m_srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED || context.getImageLayout() == m_srcLayout);
+
+       context.setImageLayout(m_dstLayout);
        m_imageMemorySize = context.getImageMemorySize();
 }
 
@@ -2110,11 +2148,11 @@ void ImageTransition::submit (SubmitContext& context)
                vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
                DE_NULL,
 
-               ALL_ACCESSES,
-               ALL_ACCESSES,
+               m_srcAccesses,
+               m_dstAccesses,
 
-               context.getImageLayout(),
-               vk::VK_IMAGE_LAYOUT_GENERAL,
+               m_srcLayout,
+               m_dstLayout,
 
                vk::VK_QUEUE_FAMILY_IGNORED,
                vk::VK_QUEUE_FAMILY_IGNORED,
@@ -2127,7 +2165,7 @@ void ImageTransition::submit (SubmitContext& context)
                }
        };
 
-       vkd.cmdPipelineBarrier(cmd, ALL_PIPELINE_STAGES, ALL_PIPELINE_STAGES, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
+       vkd.cmdPipelineBarrier(cmd, m_srcStages, m_dstStages, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &barrier);
 }
 
 void ImageTransition::verify (VerifyContext& context, size_t)
@@ -4920,7 +4958,7 @@ enum Op
        OP_IMAGE_DESTROY,
        OP_IMAGE_BINDMEMORY,
 
-       OP_IMAGE_TRANSITION_TO_GENERAL,
+       OP_IMAGE_TRANSITION_LAYOUT,
 
        OP_IMAGE_COPY_TO_BUFFER,
        OP_IMAGE_COPY_FROM_BUFFER,
@@ -4954,63 +4992,60 @@ enum Stage
        STAGE_RENDER_PASS
 };
 
-bool isWriteAccess (vk::VkAccessFlagBits access)
+vk::VkAccessFlags getWriteAccessFlags (void)
 {
-       switch (access)
-       {
-
-               case vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT:                   return false;
-               case vk::VK_ACCESS_INDEX_READ_BIT:                                              return false;
-               case vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT:                   return false;
-               case vk::VK_ACCESS_UNIFORM_READ_BIT:                                    return false;
-               case vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT:                   return false;
-               case vk::VK_ACCESS_SHADER_READ_BIT:                                             return false;
-               case vk::VK_ACCESS_SHADER_WRITE_BIT:                                    return true;
-               case vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT:                   return false;
-               case vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT:                  return true;
-               case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT:   return false;
-               case vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT:  return true;
-               case vk::VK_ACCESS_TRANSFER_READ_BIT:                                   return false;
-               case vk::VK_ACCESS_TRANSFER_WRITE_BIT:                                  return true;
-               case vk::VK_ACCESS_HOST_READ_BIT:                                               return false;
-               case vk::VK_ACCESS_HOST_WRITE_BIT:                                              return true;
-               case vk::VK_ACCESS_MEMORY_READ_BIT:                                             return false;
-               case vk::VK_ACCESS_MEMORY_WRITE_BIT:                                    return true;
+       return vk::VK_ACCESS_SHADER_WRITE_BIT
+               | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+               | vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
+               | vk::VK_ACCESS_TRANSFER_WRITE_BIT
+               | vk::VK_ACCESS_HOST_WRITE_BIT
+               | vk::VK_ACCESS_MEMORY_WRITE_BIT;
+}
 
-               default:
-                       DE_FATAL("Unknown access");
-                       return true;
-       }
+bool isWriteAccess (vk::VkAccessFlagBits access)
+{
+       return getWriteAccessFlags() & access;
 }
 
 class CacheState
 {
 public:
-                       CacheState                      (vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
+                                                                       CacheState                              (vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlags allowedAccesses);
 
-       bool    isValid                         (vk::VkPipelineStageFlagBits    stage,
-                                                                vk::VkAccessFlagBits                   access) const;
+       bool                                                    isValid                                 (vk::VkPipelineStageFlagBits    stage,
+                                                                                                                        vk::VkAccessFlagBits                   access) const;
 
-       void    perform                         (vk::VkPipelineStageFlagBits    stage,
-                                                                vk::VkAccessFlagBits                   access);
+       void                                                    perform                                 (vk::VkPipelineStageFlagBits    stage,
+                                                                                                                        vk::VkAccessFlagBits                   access);
 
-       void    submitCommandBuffer     (void);
+       void                                                    submitCommandBuffer             (void);
+       void                                                    waitForIdle                             (void);
 
-       void    getFullBarrier          (vk::VkPipelineStageFlags&      srcStages,
-                                                                vk::VkAccessFlags&                     srcAccesses,
-                                                                vk::VkPipelineStageFlags&      dstStages,
-                                                                vk::VkAccessFlags&                     dstAccesses) const;
+       void                                                    getFullBarrier                  (vk::VkPipelineStageFlags&      srcStages,
+                                                                                                                        vk::VkAccessFlags&                     srcAccesses,
+                                                                                                                        vk::VkPipelineStageFlags&      dstStages,
+                                                                                                                        vk::VkAccessFlags&                     dstAccesses) const;
 
-       void    barrier                         (vk::VkPipelineStageFlags       srcStages,
-                                                                vk::VkAccessFlags                      srcAccesses,
-                                                                vk::VkPipelineStageFlags       dstStages,
-                                                                vk::VkAccessFlags                      dstAccesses);
+       void                                                    barrier                                 (vk::VkPipelineStageFlags       srcStages,
+                                                                                                                        vk::VkAccessFlags                      srcAccesses,
+                                                                                                                        vk::VkPipelineStageFlags       dstStages,
+                                                                                                                        vk::VkAccessFlags                      dstAccesses);
 
-       void    fullBarrier                     (void);
+       void                                                    imageLayoutBarrier              (vk::VkPipelineStageFlags       srcStages,
+                                                                                                                        vk::VkAccessFlags                      srcAccesses,
+                                                                                                                        vk::VkPipelineStageFlags       dstStages,
+                                                                                                                        vk::VkAccessFlags                      dstAccesses);
+
+       void                                                    checkImageLayoutBarrier (vk::VkPipelineStageFlags       srcStages,
+                                                                                                                        vk::VkAccessFlags                      srcAccesses,
+                                                                                                                        vk::VkPipelineStageFlags       dstStages,
+                                                                                                                        vk::VkAccessFlags                      dstAccesses);
 
        // Everything is clean and there is no need for barriers
-       bool    isClean                         (void) const;
+       bool                                                    isClean                                 (void) const;
 
+       vk::VkPipelineStageFlags                getAllowedStages                (void) const { return m_allowedStages; }
+       vk::VkAccessFlags                               getAllowedAcceses               (void) const { return m_allowedAccesses; }
 private:
        // Limit which stages and accesses are used by the CacheState tracker
        const vk::VkPipelineStageFlags  m_allowedStages;
@@ -5019,6 +5054,8 @@ private:
        // [dstStage][srcStage] = srcAccesses
        // In stage dstStage write srcAccesses from srcStage are not yet available
        vk::VkAccessFlags                               m_unavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+       // Latest pipeline transition is not available in stage
+       bool                                                    m_unavailableLayoutTransition[PIPELINESTAGE_LAST];
        // [dstStage] = dstAccesses
        // In stage dstStage ops with dstAccesses are not yet visible
        vk::VkAccessFlags                               m_invisibleOperations[PIPELINESTAGE_LAST];
@@ -5045,6 +5082,9 @@ CacheState::CacheState (vk::VkPipelineStageFlags allowedStages, vk::VkAccessFlag
                // There are no incomplete read operations initially
                m_incompleteOperations[dstStage] = 0;
 
+               // There are no incomplete layout transitions
+               m_unavailableLayoutTransition[dstStage] = false;
+
                for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
                {
                        const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5068,7 +5108,7 @@ bool CacheState::isValid (vk::VkPipelineStageFlagBits     stage,
        const PipelineStage     dstStage        = pipelineStageFlagToPipelineStage(stage);
 
        // Previous operations are not visible to access on stage
-       if ((m_invisibleOperations[dstStage] & access) != 0)
+       if (m_unavailableLayoutTransition[dstStage] || (m_invisibleOperations[dstStage] & access) != 0)
                return false;
 
        if (isWriteAccess(access))
@@ -5120,6 +5160,21 @@ void CacheState::submitCommandBuffer (void)
                        m_allowedAccesses);
 }
 
+void CacheState::waitForIdle (void)
+{
+       // Make all writes available
+       barrier(m_allowedStages,
+                       m_allowedAccesses & getWriteAccessFlags(),
+                       m_allowedStages,
+                       0);
+
+       // Make all writes visible on device side
+       barrier(m_allowedStages,
+                       0,
+                       m_allowedStages & (~vk::VK_PIPELINE_STAGE_HOST_BIT),
+                       m_allowedAccesses);
+}
+
 void CacheState::getFullBarrier (vk::VkPipelineStageFlags&     srcStages,
                                                                 vk::VkAccessFlags&                     srcAccesses,
                                                                 vk::VkPipelineStageFlags&      dstStages,
@@ -5165,6 +5220,14 @@ void CacheState::getFullBarrier (vk::VkPipelineStageFlags&       srcStages,
                                srcStages |= dstStage_;
                                srcAccesses |= m_unavailableWriteOperations[dstStage][srcStage];
                        }
+
+                       if (m_unavailableLayoutTransition[dstStage] && !m_unavailableLayoutTransition[srcStage])
+                       {
+                               // Add dependency between srcStage and dstStage if layout transition has not completed in dstStage,
+                               // but has completed in srcStage.
+                               dstStages |= dstStage_;
+                               srcStages |= dstStage_;
+                       }
                }
        }
 
@@ -5174,6 +5237,108 @@ void CacheState::getFullBarrier (vk::VkPipelineStageFlags&      srcStages,
        DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
 }
 
+void CacheState::checkImageLayoutBarrier (vk::VkPipelineStageFlags     srcStages,
+                                                                                vk::VkAccessFlags                      srcAccesses,
+                                                                                vk::VkPipelineStageFlags       dstStages,
+                                                                                vk::VkAccessFlags                      dstAccesses)
+{
+       DE_ASSERT((srcStages & (~m_allowedStages)) == 0);
+       DE_ASSERT((srcAccesses & (~m_allowedAccesses)) == 0);
+       DE_ASSERT((dstStages & (~m_allowedStages)) == 0);
+       DE_ASSERT((dstAccesses & (~m_allowedAccesses)) == 0);
+
+       DE_UNREF(srcStages);
+       DE_UNREF(srcAccesses);
+
+       DE_UNREF(dstStages);
+       DE_UNREF(dstAccesses);
+
+#if defined(DE_DEBUG)
+       // Check that all stages have completed before srcStages or are in srcStages.
+       {
+               vk::VkPipelineStageFlags completedStages = srcStages;
+
+               for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
+               {
+                       const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+                       if ((srcStage_ & srcStages) == 0)
+                               continue;
+
+                       completedStages |= (~m_incompleteOperations[srcStage]);
+               }
+
+               DE_ASSERT((completedStages & m_allowedStages) == m_allowedStages);
+       }
+
+       // Check that any write is available at least in one stage. Since all stages are complete even single flush is enough.
+       if ((getWriteAccessFlags() & m_allowedAccesses) != 0 && (srcAccesses & getWriteAccessFlags()) == 0)
+       {
+               bool anyWriteAvailable = false;
+
+               for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+               {
+                       const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+                       if ((dstStage_ & m_allowedStages) == 0)
+                               continue;
+
+                       for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+                       {
+                               const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+                               if ((srcStage_ & m_allowedStages) == 0)
+                                       continue;
+
+                               if (m_unavailableWriteOperations[dstStage][srcStage] != (getWriteAccessFlags() & m_allowedAccesses))
+                               {
+                                       anyWriteAvailable = true;
+                                       break;
+                               }
+                       }
+               }
+
+               DE_ASSERT(anyWriteAvailable);
+       }
+#endif
+}
+
+void CacheState::imageLayoutBarrier (vk::VkPipelineStageFlags  srcStages,
+                                                                        vk::VkAccessFlags                      srcAccesses,
+                                                                        vk::VkPipelineStageFlags       dstStages,
+                                                                        vk::VkAccessFlags                      dstAccesses)
+{
+       checkImageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
+
+       for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
+       {
+               const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
+
+               if ((dstStage_ & m_allowedStages) == 0)
+                       continue;
+
+               // All stages are incomplete after the barrier except each dstStage in it self.
+               m_incompleteOperations[dstStage] = m_allowedStages & (~dstStage_);
+
+               // All memory operations are invisible unless they are listed in dstAccess
+               m_invisibleOperations[dstStage] = m_allowedAccesses & (~dstAccesses);
+
+               // Layout transition is unavailable in stage unless it was listed in dstStages
+               m_unavailableLayoutTransition[dstStage]= (dstStage_ & dstStages) == 0;
+
+               for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
+               {
+                       const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
+
+                       if ((srcStage_ & m_allowedStages) == 0)
+                               continue;
+
+                       // All write operations are available after layout transition
+                       m_unavailableWriteOperations[dstStage][srcStage] = 0;
+               }
+       }
+}
+
 void CacheState::barrier (vk::VkPipelineStageFlags     srcStages,
                                                  vk::VkAccessFlags                     srcAccesses,
                                                  vk::VkPipelineStageFlags      dstStages,
@@ -5188,9 +5353,11 @@ void CacheState::barrier (vk::VkPipelineStageFlags       srcStages,
        {
                vk::VkPipelineStageFlags                oldIncompleteOperations[PIPELINESTAGE_LAST];
                vk::VkAccessFlags                               oldUnavailableWriteOperations[PIPELINESTAGE_LAST][PIPELINESTAGE_LAST];
+               bool                                                    oldUnavailableLayoutTransition[PIPELINESTAGE_LAST];
 
                deMemcpy(oldIncompleteOperations, m_incompleteOperations, sizeof(oldIncompleteOperations));
                deMemcpy(oldUnavailableWriteOperations, m_unavailableWriteOperations, sizeof(oldUnavailableWriteOperations));
+               deMemcpy(oldUnavailableLayoutTransition, m_unavailableLayoutTransition, sizeof(oldUnavailableLayoutTransition));
 
                for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= srcStages; srcStage_ <<= 1)
                {
@@ -5209,6 +5376,9 @@ void CacheState::barrier (vk::VkPipelineStageFlags        srcStages,
                                // Stages that have completed before srcStage have also completed before dstStage
                                m_incompleteOperations[dstStage] &= oldIncompleteOperations[srcStage];
 
+                               // Image layout transition in srcStage are now available in dstStage
+                               m_unavailableLayoutTransition[dstStage] &= oldUnavailableLayoutTransition[srcStage];
+
                                for (vk::VkPipelineStageFlags sharedStage_ = 1; sharedStage_ <= m_allowedStages; sharedStage_ <<= 1)
                                {
                                        const PipelineStage     sharedStage                     = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)sharedStage_);
@@ -5273,6 +5443,10 @@ bool CacheState::isClean (void) const
                if (m_incompleteOperations[dstStage] != 0)
                        return false;
 
+               // Layout transition has not completed yet
+               if (m_unavailableLayoutTransition[dstStage])
+                       return false;
+
                for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
                {
                        const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
@@ -5289,34 +5463,6 @@ bool CacheState::isClean (void) const
        return true;
 }
 
-void CacheState::fullBarrier (void)
-{
-       for (vk::VkPipelineStageFlags dstStage_ = 1; dstStage_ <= m_allowedStages; dstStage_ <<= 1)
-       {
-               const PipelineStage dstStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)dstStage_);
-
-               if ((dstStage_ & m_allowedStages) == 0)
-                       continue;
-
-               // All stages have completed
-               m_incompleteOperations[dstStage] = 0;
-
-               // All operations are visible
-               m_invisibleOperations[dstStage] = 0;
-
-               for (vk::VkPipelineStageFlags srcStage_ = 1; srcStage_ <= m_allowedStages; srcStage_ <<= 1)
-               {
-                       const PipelineStage srcStage = pipelineStageFlagToPipelineStage((vk::VkPipelineStageFlagBits)srcStage_);
-
-                       if ((srcStage_ & m_allowedStages) == 0)
-                               continue;
-
-                       // All writes are available
-                       m_unavailableWriteOperations[dstStage][srcStage] = 0;
-               }
-       }
-}
-
 struct State
 {
        State (Usage usage, deUint32 seed)
@@ -5331,7 +5477,7 @@ struct State
                , hasBoundBufferMemory  (false)
                , hasImage                              (false)
                , hasBoundImageMemory   (false)
-               , imageHasGeneralLayout (false)
+               , imageLayout                   (vk::VK_IMAGE_LAYOUT_UNDEFINED)
                , imageDefined                  (false)
                , queueIdle                             (true)
                , deviceIdle                    (true)
@@ -5339,27 +5485,27 @@ struct State
        {
        }
 
-       Stage           stage;
-       CacheState      cache;
-       de::Random      rng;
+       Stage                           stage;
+       CacheState                      cache;
+       de::Random                      rng;
 
-       bool            mapped;
-       bool            hostInvalidated;
-       bool            hostFlushed;
-       bool            memoryDefined;
+       bool                            mapped;
+       bool                            hostInvalidated;
+       bool                            hostFlushed;
+       bool                            memoryDefined;
 
-       bool            hasBuffer;
-       bool            hasBoundBufferMemory;
+       bool                            hasBuffer;
+       bool                            hasBoundBufferMemory;
 
-       bool            hasImage;
-       bool            hasBoundImageMemory;
-       bool            imageHasGeneralLayout;
-       bool            imageDefined;
+       bool                            hasImage;
+       bool                            hasBoundImageMemory;
+       vk::VkImageLayout       imageLayout;
+       bool                            imageDefined;
 
-       bool            queueIdle;
-       bool            deviceIdle;
+       bool                            queueIdle;
+       bool                            deviceIdle;
 
-       bool            commandBufferIsEmpty;
+       bool                            commandBufferIsEmpty;
 };
 
 void getAvailableOps (const State& state, bool supportsBuffers, bool supportsImages, Usage usage, vector<Op>& ops)
@@ -5502,14 +5648,12 @@ void getAvailableOps (const State& state, bool supportsBuffers, bool supportsIma
 
                if (state.hasBoundImageMemory)
                {
-                       if (!state.imageHasGeneralLayout)
-                       {
-                               ops.push_back(OP_IMAGE_TRANSITION_TO_GENERAL);
-                       }
-                       else
+                       ops.push_back(OP_IMAGE_TRANSITION_LAYOUT);
+
                        {
                                if (usage & USAGE_TRANSFER_DST
-                                       && state.imageHasGeneralLayout
+                                       && (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+                                               || state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
                                        && state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT))
                                {
                                        ops.push_back(OP_IMAGE_COPY_FROM_BUFFER);
@@ -5518,7 +5662,8 @@ void getAvailableOps (const State& state, bool supportsBuffers, bool supportsIma
                                }
 
                                if (usage & USAGE_TRANSFER_SRC
-                                       && state.imageHasGeneralLayout
+                                       && (state.imageLayout == vk::VK_IMAGE_LAYOUT_GENERAL
+                                               || state.imageLayout == vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
                                        && state.imageDefined
                                        && state.cache.isValid(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT))
                                {
@@ -5529,7 +5674,7 @@ void getAvailableOps (const State& state, bool supportsBuffers, bool supportsIma
                        }
                }
 
-               // \todo Add other usages?
+               // \todo [2016-03-09 mika] Add other usages?
                if (((usage & USAGE_VERTEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT))
                        || ((usage & USAGE_INDEX_BUFFER) && state.cache.isValid(vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, vk::VK_ACCESS_INDEX_READ_BIT)))
                        ops.push_back(OP_RENDERPASS_BEGIN);
@@ -5563,7 +5708,85 @@ void getAvailableOps (const State& state, bool supportsBuffers, bool supportsIma
                DE_FATAL("Unknown stage");
 }
 
-void applyOp (State& state, const Memory& memory, Op op)
+bool layoutSupportedByUsage (Usage usage, vk::VkImageLayout layout)
+{
+       switch (layout)
+       {
+               case vk::VK_IMAGE_LAYOUT_GENERAL:
+                       return true;
+
+               case vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+                       return (usage & USAGE_COLOR_ATTACHMENT) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+                       return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+                       return (usage & USAGE_DEPTH_STENCIL_ATTACHMENT) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+                       // \todo [2016-03-09 mika] Should include input attachment
+                       return (usage & USAGE_TEXTURE_SAMPLED) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+                       return (usage & USAGE_TRANSFER_SRC) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+                       return (usage & USAGE_TRANSFER_DST) != 0;
+
+               case vk::VK_IMAGE_LAYOUT_PREINITIALIZED:
+                       return true;
+
+               default:
+                       DE_FATAL("Unknown layout");
+                       return false;
+       }
+}
+
+vk::VkImageLayout getRandomNextLayout (de::Random&                     rng,
+                                                                          Usage                                usage,
+                                                                          vk::VkImageLayout    previousLayout)
+{
+       const vk::VkImageLayout layouts[] =
+       {
+               vk::VK_IMAGE_LAYOUT_GENERAL,
+               vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+               vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+               vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+               vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+               vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+               vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+       };
+       size_t possibleLayoutCount = 0;
+
+       for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+       {
+               const vk::VkImageLayout layout = layouts[layoutNdx];
+
+               if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+                       possibleLayoutCount++;
+       }
+
+       size_t nextLayoutNdx = ((size_t)rng.getUint64()) % possibleLayoutCount;
+
+       for (size_t layoutNdx = 0; layoutNdx < DE_LENGTH_OF_ARRAY(layouts); layoutNdx++)
+       {
+               const vk::VkImageLayout layout = layouts[layoutNdx];
+
+               if (layoutSupportedByUsage(usage, layout) && layout != previousLayout)
+               {
+                       if (nextLayoutNdx == 0)
+                               return layout;
+                       else
+                               nextLayoutNdx--;
+               }
+       }
+
+       DE_FATAL("Unreachable");
+       return vk::VK_IMAGE_LAYOUT_UNDEFINED;
+}
+
+void applyOp (State& state, const Memory& memory, Op op, Usage usage)
 {
        switch (op)
        {
@@ -5604,7 +5827,7 @@ void applyOp (State& state, const Memory& memory, Op op)
 
                        state.memoryDefined = true;
                        state.imageDefined = false;
-                       state.imageHasGeneralLayout = false;
+                       state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
                        state.rng.getUint32();
                        break;
 
@@ -5657,7 +5880,7 @@ void applyOp (State& state, const Memory& memory, Op op)
 
                        state.hasImage = false;
                        state.hasBoundImageMemory = false;
-                       state.imageHasGeneralLayout = false;
+                       state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
                        state.imageDefined = false;
                        break;
 
@@ -5669,20 +5892,58 @@ void applyOp (State& state, const Memory& memory, Op op)
                        state.hasBoundImageMemory = true;
                        break;
 
-               case OP_IMAGE_TRANSITION_TO_GENERAL:
+               case OP_IMAGE_TRANSITION_LAYOUT:
+               {
                        DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
                        DE_ASSERT(state.hasImage);
                        DE_ASSERT(state.hasBoundImageMemory);
 
-                       state.imageHasGeneralLayout = true;
+                       // \todo [2016-03-09 mika] Support linear tiling and predefined data
+                       const vk::VkImageLayout         srcLayout       = state.rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+                       const vk::VkImageLayout         dstLayout       = getRandomNextLayout(state.rng, usage, srcLayout);
+
+                       vk::VkPipelineStageFlags        dirtySrcStages;
+                       vk::VkAccessFlags                       dirtySrcAccesses;
+                       vk::VkPipelineStageFlags        dirtyDstStages;
+                       vk::VkAccessFlags                       dirtyDstAccesses;
+
+                       vk::VkPipelineStageFlags        srcStages;
+                       vk::VkAccessFlags                       srcAccesses;
+                       vk::VkPipelineStageFlags        dstStages;
+                       vk::VkAccessFlags                       dstAccesses;
+
+                       state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+                       // Try masking some random bits
+                       srcStages       = dirtySrcStages;
+                       srcAccesses     = dirtySrcAccesses;
+
+                       dstStages       = state.cache.getAllowedStages() & state.rng.getUint32();
+                       dstAccesses     = state.cache.getAllowedAcceses() & state.rng.getUint32();
+
+                       // If there are no bits in dst stage mask use all stages
+                       dstStages       = dstStages ? dstStages : state.cache.getAllowedStages();
+
+                       if (!srcStages)
+                               srcStages = dstStages;
+
+                       if (srcLayout == vk::VK_IMAGE_LAYOUT_UNDEFINED)
+                               state.imageDefined = false;
+
+                       state.commandBufferIsEmpty = false;
+                       state.imageLayout = dstLayout;
                        state.memoryDefined = false;
+                       state.cache.imageLayoutBarrier(srcStages, srcAccesses, dstStages, dstAccesses);
                        break;
+               }
 
                case OP_QUEUE_WAIT_FOR_IDLE:
                        DE_ASSERT(state.stage == STAGE_HOST);
                        DE_ASSERT(!state.queueIdle);
 
                        state.queueIdle = true;
+
+                       state.cache.waitForIdle();
                        break;
 
                case OP_DEVICE_WAIT_FOR_IDLE:
@@ -5691,6 +5952,8 @@ void applyOp (State& state, const Memory& memory, Op op)
 
                        state.queueIdle = true;
                        state.deviceIdle = true;
+
+                       state.cache.waitForIdle();
                        break;
 
                case OP_COMMAND_BUFFER_BEGIN:
@@ -5706,7 +5969,6 @@ void applyOp (State& state, const Memory& memory, Op op)
                        state.stage = STAGE_HOST;
                        state.queueIdle = false;
                        state.deviceIdle = false;
-                       // \todo Should this set all device reads ready?
                        break;
 
                case OP_BUFFER_COPY_FROM_BUFFER:
@@ -5722,7 +5984,7 @@ void applyOp (State& state, const Memory& memory, Op op)
                        state.commandBufferIsEmpty = false;
                        state.memoryDefined = true;
                        state.imageDefined = false;
-                       state.imageHasGeneralLayout = false;
+                       state.imageLayout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
                        state.cache.perform(vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_ACCESS_TRANSFER_WRITE_BIT);
                        break;
 
@@ -5872,7 +6134,8 @@ de::MovePtr<Command> createHostCommand (Op                                        op,
 
 de::MovePtr<CmdCommand> createCmdCommand (de::Random&  rng,
                                                                                  const State&  state,
-                                                                                 Op                    op)
+                                                                                 Op                    op,
+                                                                                 Usage                 usage)
 {
        switch (op)
        {
@@ -5884,7 +6147,42 @@ de::MovePtr<CmdCommand> createCmdCommand (de::Random&    rng,
                case OP_BUFFER_COPY_TO_IMAGE:                   return de::MovePtr<CmdCommand>(new BufferCopyToImage());
                case OP_BUFFER_COPY_FROM_IMAGE:                 return de::MovePtr<CmdCommand>(new BufferCopyFromImage(rng.getUint32()));
 
-               case OP_IMAGE_TRANSITION_TO_GENERAL:    return de::MovePtr<CmdCommand>(new ImageTransition());
+               case OP_IMAGE_TRANSITION_LAYOUT:
+               {
+                       DE_ASSERT(state.stage == STAGE_COMMAND_BUFFER);
+                       DE_ASSERT(state.hasImage);
+                       DE_ASSERT(state.hasBoundImageMemory);
+
+                       const vk::VkImageLayout         srcLayout       = rng.getFloat() < 0.9f ? state.imageLayout : vk::VK_IMAGE_LAYOUT_UNDEFINED;
+                       const vk::VkImageLayout         dstLayout       = getRandomNextLayout(rng, usage, srcLayout);
+
+                       vk::VkPipelineStageFlags        dirtySrcStages;
+                       vk::VkAccessFlags                       dirtySrcAccesses;
+                       vk::VkPipelineStageFlags        dirtyDstStages;
+                       vk::VkAccessFlags                       dirtyDstAccesses;
+
+                       vk::VkPipelineStageFlags        srcStages;
+                       vk::VkAccessFlags                       srcAccesses;
+                       vk::VkPipelineStageFlags        dstStages;
+                       vk::VkAccessFlags                       dstAccesses;
+
+                       state.cache.getFullBarrier(dirtySrcStages, dirtySrcAccesses, dirtyDstStages, dirtyDstAccesses);
+
+                       // Try masking some random bits
+                       srcStages       = dirtySrcStages;
+                       srcAccesses     = dirtySrcAccesses;
+
+                       dstStages       = state.cache.getAllowedStages() & rng.getUint32();
+                       dstAccesses     = state.cache.getAllowedAcceses() & rng.getUint32();
+
+                       // If there are no bits in dst stage mask use all stages
+                       dstStages       = dstStages ? dstStages : state.cache.getAllowedStages();
+
+                       if (!srcStages)
+                               srcStages = dstStages;
+
+                       return de::MovePtr<CmdCommand>(new ImageTransition(srcStages, srcAccesses, dstStages, dstAccesses, srcLayout, dstLayout));
+               }
 
                case OP_IMAGE_COPY_TO_BUFFER:                   return de::MovePtr<CmdCommand>(new ImageCopyToBuffer());
                case OP_IMAGE_COPY_FROM_BUFFER:                 return de::MovePtr<CmdCommand>(new ImageCopyFromBuffer(rng.getUint32()));
@@ -5977,38 +6275,47 @@ de::MovePtr<CmdCommand> createRenderPassCommands (const Memory& memory,
                                                                                                  size_t&               opNdx,
                                                                                                  size_t                opCount)
 {
-       // \todo Exception safety
        vector<RenderPassCommand*>      commands;
 
-       for (; opNdx < opCount; opNdx++)
+       try
        {
-               vector<Op>      ops;
-
-               getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+               for (; opNdx < opCount; opNdx++)
+               {
+                       vector<Op>      ops;
 
-               DE_ASSERT(!ops.empty());
+                       getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
 
-               {
-                       const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+                       DE_ASSERT(!ops.empty());
 
-                       if (op == OP_RENDERPASS_END)
                        {
-                               break;
-                       }
-                       else
-                       {
-                               de::Random      rng     (state.rng);
+                               const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
 
-                               commands.push_back(createRenderPassCommand(rng, state, op).release());
-                               applyOp(state, memory, op);
+                               if (op == OP_RENDERPASS_END)
+                               {
+                                       break;
+                               }
+                               else
+                               {
+                                       de::Random      rng     (state.rng);
 
-                               DE_ASSERT(state.rng == rng);
+                                       commands.push_back(createRenderPassCommand(rng, state, op).release());
+                                       applyOp(state, memory, op, usage);
+
+                                       DE_ASSERT(state.rng == rng);
+                               }
                        }
                }
+
+               applyOp(state, memory, OP_RENDERPASS_END, usage);
+               return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
        }
+       catch (...)
+       {
+               for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+                       delete commands[commandNdx];
 
-       applyOp(state, memory, OP_RENDERPASS_END);
-       return de::MovePtr<CmdCommand>(new SubmitRenderPass(commands));
+               throw;
+       }
 }
 
 de::MovePtr<Command> createCmdCommands (const Memory&  memory,
@@ -6018,48 +6325,57 @@ de::MovePtr<Command> createCmdCommands (const Memory&   memory,
                                                                                size_t&                 opNdx,
                                                                                size_t                  opCount)
 {
-       // \todo Exception safety
        vector<CmdCommand*>     commands;
 
-       for (; opNdx < opCount; opNdx++)
+       try
        {
-               vector<Op>      ops;
+               for (; opNdx < opCount; opNdx++)
+               {
+                       vector<Op>      ops;
 
-               getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
+                       getAvailableOps(state, memory.getSupportBuffers(), memory.getSupportImages(), usage, ops);
 
-               DE_ASSERT(!ops.empty());
+                       DE_ASSERT(!ops.empty());
 
-               {
-                       const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
-
-                       if (op == OP_COMMAND_BUFFER_END)
-                       {
-                               break;
-                       }
-                       else
                        {
-                               // \note Command needs to known the state before the operation
-                               if (op == OP_RENDERPASS_BEGIN)
+                               const Op op = nextOpRng.choose<Op>(ops.begin(), ops.end());
+
+                               if (op == OP_COMMAND_BUFFER_END)
                                {
-                                       applyOp(state, memory, op);
-                                       commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+                                       break;
                                }
                                else
                                {
-                                       de::Random      rng     (state.rng);
+                                       // \note Command needs to known the state before the operation
+                                       if (op == OP_RENDERPASS_BEGIN)
+                                       {
+                                               applyOp(state, memory, op, usage);
+                                               commands.push_back(createRenderPassCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
+                                       }
+                                       else
+                                       {
+                                               de::Random      rng     (state.rng);
 
-                                       commands.push_back(createCmdCommand(rng, state, op).release());
-                                       applyOp(state, memory, op);
+                                               commands.push_back(createCmdCommand(rng, state, op, usage).release());
+                                               applyOp(state, memory, op, usage);
 
-                                       DE_ASSERT(state.rng == rng);
-                               }
+                                               DE_ASSERT(state.rng == rng);
+                                       }
 
+                               }
                        }
                }
+
+               applyOp(state, memory, OP_COMMAND_BUFFER_END, usage);
+               return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
        }
+       catch (...)
+       {
+               for (size_t commandNdx = 0; commandNdx < commands.size(); commandNdx++)
+                       delete commands[commandNdx];
 
-       applyOp(state, memory, OP_COMMAND_BUFFER_END);
-       return de::MovePtr<Command>(new SubmitCommandBuffer(commands));
+               throw;
+       }
 }
 
 void createCommands (vector<Command*>&                 commands,
@@ -6088,7 +6404,7 @@ void createCommands (vector<Command*>&                    commands,
 
                        if (op == OP_COMMAND_BUFFER_BEGIN)
                        {
-                               applyOp(state, memory, op);
+                               applyOp(state, memory, op, usage);
                                commands.push_back(createCmdCommands(memory, nextOpRng, state, usage, opNdx, opCount).release());
                        }
                        else
@@ -6096,7 +6412,7 @@ void createCommands (vector<Command*>&                    commands,
                                de::Random      rng     (state.rng);
 
                                commands.push_back(createHostCommand(op, rng, usage, sharingMode).release());
-                               applyOp(state, memory, op);
+                               applyOp(state, memory, op, usage);
 
                                // Make sure that random generator is in sync
                                DE_ASSERT(state.rng == rng);
@@ -6319,7 +6635,7 @@ MemoryTestInstance::MemoryTestInstance (::vkt::Context& context, const TestConfi
 
 tcu::TestStatus MemoryTestInstance::iterate (void)
 {
-       // \todo Split different stages over multiple iterations
+       // \todo [2016-03-09 mika] Split different stages over multiple iterations
        if (m_memoryTypeNdx < m_memoryProperties.memoryTypeCount)
        {
                TestLog&                                                                        log                                     = m_context.getTestContext().getLog();
index 6e6426c..0e731a2 100644 (file)
@@ -101,6 +101,18 @@ static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* ds
                typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
 }
 
+static void floorAll (vector<float>& values)
+{
+       for (size_t i = 0; i < values.size(); i++)
+               values[i] = deFloatFloor(values[i]);
+}
+
+static void floorAll (vector<Vec4>& values)
+{
+       for (size_t i = 0; i < values.size(); i++)
+               values[i] = floor(values[i]);
+}
+
 struct CaseParameter
 {
        const char*             name;
@@ -571,6 +583,9 @@ tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
 
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats1);
+
        for (size_t ndx = 0; ndx < numElements; ++ndx)
                outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
 
@@ -777,6 +792,9 @@ tcu::TestCaseGroup* createOpCopyObjectGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
 
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats);
+
        for (size_t ndx = 0; ndx < numElements; ++ndx)
                outputFloats[ndx] = inputFloats[ndx] + 7.5f;
 
@@ -1037,15 +1055,12 @@ tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
        fillRandomScalars(rnd, -300.f, 300.f, &inputFloats3[0], numElements);
        fillRandomScalars(rnd, -300.f, 300.f, &inputFloats4[0], numElements);
 
-
-       for (size_t ndx = 0; ndx < numElements; ++ndx)
-       {
-               inputFloats0[ndx] = deFloatFloor(inputFloats0[ndx]);
-               inputFloats1[ndx] = deFloatFloor(inputFloats1[ndx]);
-               inputFloats2[ndx] = deFloatFloor(inputFloats2[ndx]);
-               inputFloats3[ndx] = deFloatFloor(inputFloats3[ndx]);
-               inputFloats4[ndx] = deFloatFloor(inputFloats4[ndx]);
-       }
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats0);
+       floorAll(inputFloats1);
+       floorAll(inputFloats2);
+       floorAll(inputFloats3);
+       floorAll(inputFloats4);
 
        for (size_t ndx = 0; ndx < numElements; ++ndx)
                outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
@@ -1396,6 +1411,9 @@ tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
 
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats);
+
        for (size_t ndx = 0; ndx < numElements; ++ndx)
        {
                switch (ndx % 3)
@@ -1598,8 +1616,8 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
-       for (size_t ndx = 0; ndx < numElements; ++ndx)
-               inputFloats[ndx] = deFloatFloor(inputFloats[ndx]);
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats);
 
        for (size_t ndx = 0; ndx <= 50; ++ndx)
                outputFloats[ndx] = -inputFloats[ndx];
@@ -2928,6 +2946,9 @@ tcu::TestCaseGroup* createSelectionControlGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats);
+
        for (size_t ndx = 0; ndx < numElements; ++ndx)
                outputFloats[ndx] = inputFloats[ndx] + (inputFloats[ndx] > 10.f ? 1.f : -1.f);
 
@@ -3020,6 +3041,9 @@ tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
 
        fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
 
+       // CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
+       floorAll(inputFloats);
+
        for (size_t ndx = 0; ndx < numElements; ++ndx)
                outputFloats[ndx] = inputFloats[ndx] + 10.f;
 
index e6cdbc2..695d17b 100644 (file)
@@ -209,7 +209,7 @@ void createVulkanBuffer (const BufferParameters& bufferParameters, Buffer& buffe
                        range.offset    = newMemory->getOffset();
                        range.size              = bufferParameters.size;
 
-                       deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, bufferParameters.size);
+                       deMemcpy(newMemory->getHostPtr(), bufferParameters.memory, (size_t)bufferParameters.size);
                        VK_CHECK(deviceInterface.flushMappedMemoryRanges(device, 1, &range));
 
                        barrier.sType                   = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
index 29b8973..42c0553 100644 (file)
@@ -45,6 +45,7 @@
 #include "vkTypeUtil.hpp"
 #include "vkWsiPlatform.hpp"
 #include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
 
 #include "tcuTestLog.hpp"
 #include "tcuFormatUtil.hpp"
@@ -108,9 +109,10 @@ void checkAllSupported (const Extensions& supportedExtensions, const vector<stri
        }
 }
 
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface&       vkp,
-                                                                               const Extensions&                       supportedExtensions,
-                                                                               Type                                            wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface&               vkp,
+                                                                               const Extensions&                               supportedExtensions,
+                                                                               Type                                                    wsiType,
+                                                                               const VkAllocationCallbacks*    pAllocator      = DE_NULL)
 {
        vector<string>  extensions;
 
@@ -119,7 +121,7 @@ Move<VkInstance> createInstanceWithWsi (const PlatformInterface&    vkp,
 
        checkAllSupported(supportedExtensions, extensions);
 
-       return createDefaultInstance(vkp, vector<string>(), extensions);
+       return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
 }
 
 struct InstanceHelper
@@ -128,12 +130,13 @@ struct InstanceHelper
        Unique<VkInstance>                                      instance;
        const InstanceDriver                            vki;
 
-       InstanceHelper (Context& context, Type wsiType)
+       InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
                : supportedExtensions   (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
                                                                                                                                          DE_NULL))
                , instance                              (createInstanceWithWsi(context.getPlatformInterface(),
                                                                                                           supportedExtensions,
-                                                                                                          wsiType))
+                                                                                                          wsiType,
+                                                                                                          pAllocator))
                , vki                                   (context.getPlatformInterface(), *instance)
        {}
 };
@@ -196,6 +199,89 @@ tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
        return tcu::TestStatus::pass("Creating surface succeeded");
 }
 
+tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
+{
+       AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
+       tcu::TestLog&                           log                                     = context.getTestContext().getLog();
+
+       {
+               const InstanceHelper            instHelper      (context, wsiType, allocationRecorder.getCallbacks());
+               const NativeObjects                     native          (context, instHelper.supportedExtensions, wsiType);
+               const Unique<VkSurfaceKHR>      surface         (createSurface(instHelper.vki,
+                                                                                                                          *instHelper.instance,
+                                                                                                                          wsiType,
+                                                                                                                          *native.display,
+                                                                                                                          *native.window,
+                                                                                                                          allocationRecorder.getCallbacks()));
+
+               if (!validateAndLog(log,
+                                                       allocationRecorder,
+                                                       (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)         |
+                                                       (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+                       return tcu::TestStatus::fail("Detected invalid system allocation callback");
+       }
+
+       if (!validateAndLog(log, allocationRecorder, 0u))
+               return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+       if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
+               return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+       else
+               return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
+}
+
+tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
+{
+       tcu::TestLog&   log     = context.getTestContext().getLog();
+
+       for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
+       {
+               AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
+               DeterministicFailAllocator      failingAllocator        (allocationRecorder.getCallbacks(), numPassingAllocs);
+               bool                                            gotOOM                          = false;
+
+               log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+               try
+               {
+                       const InstanceHelper            instHelper      (context, wsiType, failingAllocator.getCallbacks());
+                       const NativeObjects                     native          (context, instHelper.supportedExtensions, wsiType);
+                       const Unique<VkSurfaceKHR>      surface         (createSurface(instHelper.vki,
+                                                                                                                                  *instHelper.instance,
+                                                                                                                                  wsiType,
+                                                                                                                                  *native.display,
+                                                                                                                                  *native.window,
+                                                                                                                                  failingAllocator.getCallbacks()));
+
+                       if (!validateAndLog(log,
+                                                               allocationRecorder,
+                                                               (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)         |
+                                                               (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
+                               return tcu::TestStatus::fail("Detected invalid system allocation callback");
+               }
+               catch (const OutOfMemoryError& e)
+               {
+                       log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+                       gotOOM = true;
+               }
+
+               if (!validateAndLog(log, allocationRecorder, 0u))
+                       return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+               if (!gotOOM)
+               {
+                       log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+                       if (numPassingAllocs == 0)
+                               return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+                       else
+                               return tcu::TestStatus::pass("OOM simulation completed");
+               }
+       }
+
+       return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
+}
+
 deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
 {
        deUint32        numFamilies             = 0;
@@ -524,11 +610,13 @@ void createSurfaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
 {
        const PlatformProperties&       platformProperties      = getPlatformProperties(wsiType);
 
-       addFunctionCase(testGroup, "create",                            "Create surface",                               createSurfaceTest,                              wsiType);
-       addFunctionCase(testGroup, "query_support",                     "Query surface support",                querySurfaceSupportTest,                wsiType);
-       addFunctionCase(testGroup, "query_capabilities",        "Query surface capabilities",   querySurfaceCapabilitiesTest,   wsiType);
-       addFunctionCase(testGroup, "query_formats",                     "Query surface formats",                querySurfaceFormatsTest,                wsiType);
-       addFunctionCase(testGroup, "query_present_modes",       "Query surface present modes",  querySurfacePresentModesTest,   wsiType);
+       addFunctionCase(testGroup, "create",                                    "Create surface",                                               createSurfaceTest,                                      wsiType);
+       addFunctionCase(testGroup, "create_custom_allocator",   "Create surface with custom allocator", createSurfaceCustomAllocatorTest,       wsiType);
+       addFunctionCase(testGroup, "create_simulate_oom",               "Create surface with simulating OOM",   createSurfaceSimulateOOMTest,           wsiType);
+       addFunctionCase(testGroup, "query_support",                             "Query surface support",                                querySurfaceSupportTest,                        wsiType);
+       addFunctionCase(testGroup, "query_capabilities",                "Query surface capabilities",                   querySurfaceCapabilitiesTest,           wsiType);
+       addFunctionCase(testGroup, "query_formats",                             "Query surface formats",                                querySurfaceFormatsTest,                        wsiType);
+       addFunctionCase(testGroup, "query_present_modes",               "Query surface present modes",                  querySurfacePresentModesTest,           wsiType);
 
        if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
                addFunctionCase(testGroup, "initial_size",      "Create surface with initial window size set",  createSurfaceInitialSizeTest,   wsiType);
index 5f977b8..1342955 100644 (file)
@@ -45,6 +45,7 @@
 #include "vkTypeUtil.hpp"
 #include "vkWsiPlatform.hpp"
 #include "vkWsiUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
 
 #include "tcuTestLog.hpp"
 #include "tcuFormatUtil.hpp"
@@ -89,9 +90,10 @@ void checkAllSupported (const Extensions& supportedExtensions, const vector<stri
        }
 }
 
-Move<VkInstance> createInstanceWithWsi (const PlatformInterface&       vkp,
-                                                                               const Extensions&                       supportedExtensions,
-                                                                               Type                                            wsiType)
+Move<VkInstance> createInstanceWithWsi (const PlatformInterface&               vkp,
+                                                                               const Extensions&                               supportedExtensions,
+                                                                               Type                                                    wsiType,
+                                                                               const VkAllocationCallbacks*    pAllocator      = DE_NULL)
 {
        vector<string>  extensions;
 
@@ -100,7 +102,7 @@ Move<VkInstance> createInstanceWithWsi (const PlatformInterface&    vkp,
 
        checkAllSupported(supportedExtensions, extensions);
 
-       return createDefaultInstance(vkp, vector<string>(), extensions);
+       return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
 }
 
 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
@@ -110,10 +112,11 @@ VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
        return features;
 }
 
-Move<VkDevice> createDeviceWithWsi (const InstanceInterface&   vki,
-                                                                       VkPhysicalDevice                        physicalDevice,
-                                                                       const Extensions&                       supportedExtensions,
-                                                                       const deUint32                          queueFamilyIndex)
+Move<VkDevice> createDeviceWithWsi (const InstanceInterface&           vki,
+                                                                       VkPhysicalDevice                                physicalDevice,
+                                                                       const Extensions&                               supportedExtensions,
+                                                                       const deUint32                                  queueFamilyIndex,
+                                                                       const VkAllocationCallbacks*    pAllocator = DE_NULL)
 {
        const float                                             queuePriorities[]       = { 1.0f };
        const VkDeviceQueueCreateInfo   queueInfos[]            =
@@ -149,7 +152,7 @@ Move<VkDevice> createDeviceWithWsi (const InstanceInterface&        vki,
                        TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
        }
 
-       return createDevice(vki, physicalDevice, &deviceParams, (const VkAllocationCallbacks*)DE_NULL);
+       return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
 }
 
 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
@@ -191,12 +194,13 @@ struct InstanceHelper
        const Unique<VkInstance>                        instance;
        const InstanceDriver                            vki;
 
-       InstanceHelper (Context& context, Type wsiType)
+       InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
                : supportedExtensions   (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
                                                                                                                                          DE_NULL))
                , instance                              (createInstanceWithWsi(context.getPlatformInterface(),
                                                                                                           supportedExtensions,
-                                                                                                          wsiType))
+                                                                                                          wsiType,
+                                                                                                          pAllocator))
                , vki                                   (context.getPlatformInterface(), *instance)
        {}
 };
@@ -216,13 +220,18 @@ struct DeviceHelper
        const DeviceDriver              vkd;
        const VkQueue                   queue;
 
-       DeviceHelper (Context& context, const InstanceInterface& vki, VkInstance instance, VkSurfaceKHR surface)
+       DeviceHelper (Context&                                          context,
+                                 const InstanceInterface&              vki,
+                                 VkInstance                                    instance,
+                                 VkSurfaceKHR                                  surface,
+                                 const VkAllocationCallbacks*  pAllocator = DE_NULL)
                : physicalDevice        (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
                , queueFamilyIndex      (chooseQueueFamilyIndex(vki, physicalDevice, surface))
                , device                        (createDeviceWithWsi(vki,
                                                                                                 physicalDevice,
                                                                                                 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
-                                                                                                queueFamilyIndex))
+                                                                                                queueFamilyIndex,
+                                                                                                pAllocator))
                , vkd                           (vki, *device)
                , queue                         (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
        {
@@ -572,6 +581,75 @@ tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
        return tcu::TestStatus::pass("Creating swapchain succeeded");
 }
 
+tcu::TestStatus createSwapchainSimulateOOMTest (Context& context, TestParameters params)
+{
+       tcu::TestLog&   log     = context.getTestContext().getLog();
+
+       // \note This is a little counter-intuitive order (iterating on callback count until all cases pass)
+       //               but since cases depend on what device reports, it is the only easy way. In practice
+       //               we should see same number of total callbacks (and executed code) regardless of the
+       //               loop order.
+
+       for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 16*1024u; ++numPassingAllocs)
+       {
+               AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
+               DeterministicFailAllocator      failingAllocator        (allocationRecorder.getCallbacks(), numPassingAllocs);
+               bool                                            gotOOM                          = false;
+
+               log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
+
+               try
+               {
+                       const InstanceHelper                                    instHelper      (context, params.wsiType, failingAllocator.getCallbacks());
+                       const NativeObjects                                             native          (context, instHelper.supportedExtensions, params.wsiType);
+                       const Unique<VkSurfaceKHR>                              surface         (createSurface(instHelper.vki,
+                                                                                                                                                          *instHelper.instance,
+                                                                                                                                                          params.wsiType,
+                                                                                                                                                          *native.display,
+                                                                                                                                                          *native.window,
+                                                                                                                                                          failingAllocator.getCallbacks()));
+                       const DeviceHelper                                              devHelper       (context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
+                       const vector<VkSwapchainCreateInfoKHR>  cases           (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
+
+                       for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
+                       {
+                               VkSwapchainCreateInfoKHR        curParams       = cases[caseNdx];
+
+                               curParams.surface                               = *surface;
+                               curParams.queueFamilyIndexCount = 1u;
+                               curParams.pQueueFamilyIndices   = &devHelper.queueFamilyIndex;
+
+                               context.getTestContext().getLog()
+                                       << TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << TestLog::EndMessage;
+
+                               {
+                                       const Unique<VkSwapchainKHR>    swapchain       (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
+                               }
+                       }
+               }
+               catch (const OutOfMemoryError& e)
+               {
+                       log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
+                       gotOOM = true;
+               }
+
+               if (!validateAndLog(log, allocationRecorder, 0u))
+                       return tcu::TestStatus::fail("Detected invalid system allocation callback");
+
+               if (!gotOOM)
+               {
+                       log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
+
+                       if (numPassingAllocs == 0)
+                               return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
+                       else
+                               return tcu::TestStatus::pass("OOM simulation completed");
+               }
+       }
+
+       return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
+}
+
 struct GroupParameters
 {
        typedef FunctionInstance1<TestParameters>::Function     Function;
@@ -604,7 +682,8 @@ void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters para
 
 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
 {
-       addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+       addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
+       addTestGroup(testGroup, "simulate_oom",         "Simulate OOM using callbacks during swapchain construction",   populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
 }
 
 } // wsi
index b41ef7b..ba267d5 100644 (file)
@@ -84,6 +84,7 @@ DE_DECLARE_COMMAND_LINE_OPT(LogImages,                                        bool);
 DE_DECLARE_COMMAND_LINE_OPT(LogShaderSources,                  bool);
 DE_DECLARE_COMMAND_LINE_OPT(TestOOM,                                   bool);
 DE_DECLARE_COMMAND_LINE_OPT(VKDeviceID,                                        int);
+DE_DECLARE_COMMAND_LINE_OPT(LogFlush,                                  bool);
 
 static void parseIntList (const char* src, std::vector<int>* dst)
 {
@@ -168,7 +169,8 @@ void registerOptions (de::cmdline::Parser& parser)
                << 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<LogShaderSources>             (DE_NULL,       "deqp-log-shader-sources",              "Enable or disable logging of shader sources",          s_enableNames,          "enable")
-               << Option<TestOOM>                              (DE_NULL,       "deqp-test-oom",                                "Run tests that exhaust memory on purpose",                     s_enableNames,          TEST_OOM_DEFAULT);
+               << Option<TestOOM>                              (DE_NULL,       "deqp-test-oom",                                "Run tests that exhaust memory on purpose",                     s_enableNames,          TEST_OOM_DEFAULT)
+               << Option<LogFlush>             (DE_NULL,   "deqp-log-flush",               "Enable or disable log file fflush",                s_enableNames,      "enable");
 }
 
 void registerLegacyOptions (de::cmdline::Parser& parser)
@@ -725,6 +727,9 @@ bool CommandLine::parse (int argc, const char* const* argv)
        if (!m_cmdLine.getOption<opt::LogShaderSources>())
                m_logFlags |= QP_TEST_LOG_EXCLUDE_SHADER_SOURCES;
 
+       if (!m_cmdLine.getOption<opt::LogFlush>())
+               m_logFlags |= QP_TEST_LOG_NO_FLUSH;
+
        if ((m_cmdLine.hasOption<opt::CasePath>()?1:0) +
                (m_cmdLine.hasOption<opt::CaseList>()?1:0) +
                (m_cmdLine.hasOption<opt::CaseListFile>()?1:0) +
index dc21619..34882eb 100644 (file)
@@ -146,7 +146,7 @@ void writeXmlCaselistsToFiles (TestPackageRoot& root, TestContext& testCtx, cons
                        if (!file)
                                throw Exception("Failed to open " + filename);
 
-                       writer = qpXmlWriter_createFileWriter(file, DE_FALSE);
+                       writer = qpXmlWriter_createFileWriter(file, DE_FALSE, DE_FALSE);
                        if (!writer)
                                throw Exception("XML writer creation failed");
 
index 26c7923..327e232 100644 (file)
@@ -350,7 +350,7 @@ qpTestLog* qpTestLog_createFileLog (const char* fileName, deUint32 flags)
        }
 
        log->flags                      = flags;
-       log->writer                     = qpXmlWriter_createFileWriter(log->outputFile, 0);
+       log->writer                     = qpXmlWriter_createFileWriter(log->outputFile, 0, !(flags & QP_TEST_LOG_NO_FLUSH));
        log->lock                       = deMutex_create(DE_NULL);
        log->isSessionOpen      = DE_FALSE;
        log->isCaseOpen         = DE_FALSE;
@@ -419,7 +419,8 @@ deBool qpTestLog_startCase (qpTestLog* log, const char* testCasePath, qpTestCase
        /* Flush XML and write out #beginTestCaseResult. */
        qpXmlWriter_flush(log->writer);
        fprintf(log->outputFile, "\n#beginTestCaseResult %s\n", testCasePath);
-       qpTestLog_flushFile(log);
+       if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+               qpTestLog_flushFile(log);
 
        log->isCaseOpen = DE_TRUE;
 
@@ -473,7 +474,8 @@ deBool qpTestLog_endCase (qpTestLog* log, qpTestResult result, const char* resul
        /* Flush XML and write #endTestCaseResult. */
        qpXmlWriter_flush(log->writer);
        fprintf(log->outputFile, "\n#endTestCaseResult\n");
-       qpTestLog_flushFile(log);
+       if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
+               qpTestLog_flushFile(log);
 
        log->isCaseOpen = DE_FALSE;
 
index aa74fa7..f12454f 100644 (file)
@@ -133,7 +133,8 @@ typedef enum qpImageFormat_e
 typedef enum qpTestLogFlag_e
 {
        QP_TEST_LOG_EXCLUDE_IMAGES                      = (1<<0),               /*!< Do not log images. This reduces log size considerably.                     */
-       QP_TEST_LOG_EXCLUDE_SHADER_SOURCES      = (1<<1)                /*!< Do not log shader sources. Helps to reduce log size further.       */
+       QP_TEST_LOG_EXCLUDE_SHADER_SOURCES      = (1<<1),               /*!< Do not log shader sources. Helps to reduce log size further.       */
+       QP_TEST_LOG_NO_FLUSH                            = (1<<2)                /*!< Do not do a fflush after writing the log.                                          */
 } qpTestLogFlag;
 
 /* Shader type. */
index 6921dab..97ee987 100644 (file)
@@ -36,6 +36,7 @@
 struct qpXmlWriter_s
 {
        FILE*                           outputFile;
+       deBool                          flushAfterWrite;
 
        deBool                          xmlPrevIsStartElement;
        deBool                          xmlIsWriting;
@@ -114,12 +115,13 @@ static deBool writeEscaped (qpXmlWriter* writer, const char* str)
                }
        } while (!isEOS);
 
-       fflush(writer->outputFile);
+       if (writer->flushAfterWrite)
+               fflush(writer->outputFile);
        DE_ASSERT(d == &buf[0]); /* buffer must be empty */
        return DE_TRUE;
 }
 
-qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression)
+qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression, deBool flushAfterWrite)
 {
        qpXmlWriter* writer = (qpXmlWriter*)deCalloc(sizeof(qpXmlWriter));
        if (!writer)
@@ -128,6 +130,7 @@ qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompressi
        DE_UNREF(useCompression); /* no compression supported. */
 
        writer->outputFile = outputFile;
+       writer->flushAfterWrite = flushAfterWrite;
 
        return writer;
 }
index ebba428..bb63bde 100644 (file)
@@ -85,9 +85,10 @@ DE_INLINE qpXmlAttribute qpSetBoolAttrib (const char* name, deBool value)
  * \brief Create a file based XML Writer instance
  * \param fileName Name of the file
  * \param useCompression Set to DE_TRUE to use compression, if supported by implementation
+ * \param flushAfterWrite Set to DE_TRUE to call fflush after writing each XML token
  * \return qpXmlWriter instance, or DE_NULL if cannot create file
  *//*--------------------------------------------------------------------*/
-qpXmlWriter*   qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression);
+qpXmlWriter*   qpXmlWriter_createFileWriter (FILE* outFile, deBool useCompression, deBool flushAfterWrite);
 
 /*--------------------------------------------------------------------*//*!
  * \brief XML Writer instance