Use the correct stencilInitialLayout for unused resolve targets with separate stencil
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / renderpass / vktRenderPassDepthStencilResolveTests.cpp
index ce2092c..730b7c6 100644 (file)
@@ -49,7 +49,9 @@
 #include "deUniquePtr.hpp"
 #include "deSharedPtr.hpp"
 #include "deMath.h"
+
 #include <limits>
+#include <map>
 
 using namespace vk;
 
@@ -108,6 +110,38 @@ struct TestConfig
        deUint8                                         stencilExpectedValue;
        bool                                            separateDepthStencilLayouts;
        bool                                            unusedResolve;
+       tcu::Maybe<VkFormat>            compatibleFormat;
+       bool                                            sampleMask;
+};
+
+// Auxiliar class to group depth formats by compatibility in bit size and format. Note there is at most one alternative format for
+// each given format as of the time this comment is being written, and the alternative (compatible) format for a given format can
+// only remove aspects but not add them. That is, we cannot use a depth/stencil attachment to resolve a depth-only attachment.
+//
+// See:
+//     * VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03181
+//     * VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03182
+class DepthCompatibilityManager
+{
+public:
+       DepthCompatibilityManager ()
+               : m_compatibleFormats()
+       {
+               m_compatibleFormats[VK_FORMAT_D32_SFLOAT_S8_UINT]       = VK_FORMAT_D32_SFLOAT;
+               m_compatibleFormats[VK_FORMAT_D16_UNORM_S8_UINT]        = VK_FORMAT_D16_UNORM;
+               m_compatibleFormats[VK_FORMAT_D24_UNORM_S8_UINT]        = VK_FORMAT_X8_D24_UNORM_PACK32;
+       }
+
+       VkFormat getAlternativeFormat (VkFormat format) const
+       {
+               const auto itr = m_compatibleFormats.find(format);
+               if (itr != end(m_compatibleFormats))
+                       return itr->second;
+               return VK_FORMAT_UNDEFINED;
+       }
+
+private:
+       std::map<VkFormat, VkFormat> m_compatibleFormats;
 };
 
 float get16bitDepthComponent(deUint8* pixelPtr)
@@ -140,6 +174,7 @@ public:
 
 protected:
        bool                                            isFeaturesSupported                             (void);
+       bool                                            isSupportedFormat                               (Context& context, VkFormat format) const;
        VkSampleCountFlagBits           sampleCountBitFromSampleCount   (deUint32 count) const;
 
        VkImageSp                                       createImage                                             (deUint32 sampleCount, VkImageUsageFlags additionalUsage = 0u);
@@ -148,10 +183,11 @@ protected:
        AllocationSp                            createBufferMemory                              (void);
        VkBufferSp                                      createBuffer                                    (void);
 
-       Move<VkRenderPass>                      createRenderPass                                (void);
+       Move<VkRenderPass>                      createRenderPass                                (VkFormat vkformat, deUint32 renderPassNo);
+       Move<VkRenderPass>                      createRenderPassCompatible              (void);
        Move<VkFramebuffer>                     createFramebuffer                               (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView);
        Move<VkPipelineLayout>          createRenderPipelineLayout              (void);
-       Move<VkPipeline>                        createRenderPipeline                    (VkRenderPass renderPass, VkPipelineLayout renderPipelineLayout);
+       Move<VkPipeline>                        createRenderPipeline                    (VkRenderPass renderPass, deUint32 renderPassNo, VkPipelineLayout renderPipelineLayout);
 
        void                                            submit                                                  (void);
        bool                                            verifyDepth                                             (void);
@@ -177,10 +213,12 @@ protected:
        VkBufferSp                                              m_buffer;
        AllocationSp                                    m_bufferMemory;
 
-       Unique<VkRenderPass>                    m_renderPass;
-       Unique<VkFramebuffer>                   m_framebuffer;
+       deUint32                                                m_numRenderPasses;
+       std::vector<Move<VkRenderPass>> m_renderPass;
+       Unique<VkRenderPass>                    m_renderPassCompatible;
+       Move<VkFramebuffer>                             m_framebuffer;
        Unique<VkPipelineLayout>                m_renderPipelineLayout;
-       Unique<VkPipeline>                              m_renderPipeline;
+       std::vector<Move<VkPipeline>>   m_renderPipeline;
 };
 
 DepthStencilResolveTest::DepthStencilResolveTest (Context& context, TestConfig config)
@@ -205,11 +243,16 @@ DepthStencilResolveTest::DepthStencilResolveTest (Context& context, TestConfig c
        , m_buffer                                      (createBuffer())
        , m_bufferMemory                        (createBufferMemory())
 
-       , m_renderPass                          (createRenderPass())
-       , m_framebuffer                         (createFramebuffer(*m_renderPass, m_multisampleImageView, m_singlesampleImageView))
+       , m_numRenderPasses                     ((m_config.verifyBuffer == VB_DEPTH || !m_config.sampleMask) ? 1u : m_config.sampleCount)
+       , m_renderPassCompatible        (createRenderPassCompatible())
        , m_renderPipelineLayout        (createRenderPipelineLayout())
-       , m_renderPipeline                      (createRenderPipeline(*m_renderPass, *m_renderPipelineLayout))
 {
+       for (deUint32 i = 0; i < m_numRenderPasses; i++)
+       {
+               m_renderPass.push_back(createRenderPass(m_config.format, i));
+               m_renderPipeline.push_back(createRenderPipeline(*m_renderPass[i], i, *m_renderPipelineLayout));
+       }
+       m_framebuffer = createFramebuffer(*m_renderPass[0], m_multisampleImageView, m_singlesampleImageView);
 }
 
 DepthStencilResolveTest::~DepthStencilResolveTest (void)
@@ -241,10 +284,12 @@ bool DepthStencilResolveTest::isFeaturesSupported()
 
        // check if both modes are supported
        VkResolveModeFlagBits depthResolveMode          = m_config.depthResolveMode;
-       VkResolveModeFlagBits stencilResolveMode                = m_config.stencilResolveMode;
+       VkResolveModeFlagBits stencilResolveMode        = m_config.stencilResolveMode;
+
        if ((depthResolveMode != VK_RESOLVE_MODE_NONE) &&
                !(depthResolveMode & dsResolveProperties.supportedDepthResolveModes))
                TCU_THROW(NotSupportedError, "Depth resolve mode not supported");
+
        if ((stencilResolveMode != VK_RESOLVE_MODE_NONE) &&
                !(stencilResolveMode & dsResolveProperties.supportedStencilResolveModes))
                TCU_THROW(NotSupportedError, "Stencil resolve mode not supported");
@@ -265,6 +310,13 @@ bool DepthStencilResolveTest::isFeaturesSupported()
                TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes");
        }
 
+       // Check alternative format support if needed.
+       if (m_config.compatibleFormat)
+       {
+               if (! isSupportedFormat(m_context, m_config.compatibleFormat.get()))
+                       TCU_THROW(NotSupportedError, "Alternative image format for compatibility test not supported");
+       }
+
        return true;
 }
 
@@ -382,70 +434,8 @@ VkImageViewSp DepthStencilResolveTest::createImageView (VkImageSp image, deUint3
        return safeSharedPtr(new Unique<VkImageView>(vk::createImageView(m_vkd, m_device, &pCreateInfo)));
 }
 
-Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
+Move<VkRenderPass> DepthStencilResolveTest::createRenderPass(VkFormat vkformat, deUint32 renderPassNo)
 {
-       // When the depth/stencil resolve attachment is unused, it needs to be cleared outside the render pass so it has the expected values.
-       if (m_config.unusedResolve)
-       {
-               const tcu::TextureFormat                        format                  (mapVkFormat(m_config.format));
-               const Unique<VkCommandBuffer>           commandBuffer   (allocateCommandBuffer(m_vkd, m_device, *m_commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
-               const vk::VkImageSubresourceRange       imageRange              =
-               {
-                       ((tcu::hasDepthComponent(format.order)          ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_DEPTH_BIT)    : 0u) |
-                        (tcu::hasStencilComponent(format.order)        ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_STENCIL_BIT)  : 0u)),
-                       0u,
-                       VK_REMAINING_MIP_LEVELS,
-                       0u,
-                       VK_REMAINING_ARRAY_LAYERS,
-               };
-               const vk::VkImageMemoryBarrier          preBarrier              =
-               {
-                       vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-                       nullptr,
-
-                       // src and dst access masks.
-                       0,
-                       vk::VK_ACCESS_TRANSFER_WRITE_BIT,
-
-                       // old and new layouts.
-                       vk::VK_IMAGE_LAYOUT_UNDEFINED,
-                       vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-
-                       VK_QUEUE_FAMILY_IGNORED,
-                       VK_QUEUE_FAMILY_IGNORED,
-
-                       **m_singlesampleImage,
-                       imageRange,
-               };
-               const vk::VkImageMemoryBarrier          postBarrier             =
-               {
-                       vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-                       nullptr,
-
-                       // src and dst access masks.
-                       vk::VK_ACCESS_TRANSFER_WRITE_BIT,
-                       0,
-
-                       // old and new layouts.
-                       vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                       vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-
-                       VK_QUEUE_FAMILY_IGNORED,
-                       VK_QUEUE_FAMILY_IGNORED,
-
-                       **m_singlesampleImage,
-                       imageRange,
-               };
-
-               vk::beginCommandBuffer(m_vkd, commandBuffer.get());
-                       m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preBarrier);
-                       m_vkd.cmdClearDepthStencilImage(commandBuffer.get(), **m_singlesampleImage, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_config.clearValue, 1u, &imageRange);
-                       m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &postBarrier);
-               vk::endCommandBuffer(m_vkd, commandBuffer.get());
-
-               vk::submitCommandsAndWait(m_vkd, m_device, m_context.getUniversalQueue(), commandBuffer.get());
-       }
-
        const VkSampleCountFlagBits samples(sampleCountBitFromSampleCount(m_config.sampleCount));
 
        VkImageLayout layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@@ -457,14 +447,22 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
        };
        void * attachmentRefStencil = DE_NULL;
        VkImageLayout finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-       VkAttachmentDescriptionStencilLayoutKHR stencilFinalLayout =
+       VkAttachmentDescriptionStencilLayoutKHR multisampleStencilFinalLayout =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR,
+               DE_NULL,
+               VK_IMAGE_LAYOUT_UNDEFINED,
+               VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+       };
+       VkAttachmentDescriptionStencilLayoutKHR singlesampleStencilFinalLayout =
        {
                VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR,
                DE_NULL,
                VK_IMAGE_LAYOUT_UNDEFINED,
                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
        };
-       void * attachmentDescriptionStencil = DE_NULL;
+       void * multisampleAttachmentDescriptionStencil = DE_NULL;
+       void * singlesampleAttachmentDescriptionStencil = DE_NULL;
 
        if (m_config.separateDepthStencilLayouts)
        {
@@ -473,31 +471,47 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
                        layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR;
                        stencilLayout.stencilLayout = VK_IMAGE_LAYOUT_GENERAL;
                        finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-                       stencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
+                       multisampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
+                       singlesampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
                }
                else
                {
-                       layout = VK_IMAGE_LAYOUT_GENERAL;
+                       layout = m_config.sampleMask ? VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR : VK_IMAGE_LAYOUT_GENERAL;
                        stencilLayout.stencilLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR;
-                       finalLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
-                       stencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+                       finalLayout = VK_IMAGE_LAYOUT_GENERAL;  // This aspect should be unused.
+                       multisampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+                       singlesampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
                }
                attachmentRefStencil = &stencilLayout;
-               attachmentDescriptionStencil = &stencilFinalLayout;
+               multisampleAttachmentDescriptionStencil = &multisampleStencilFinalLayout;
+               singlesampleAttachmentDescriptionStencil = &singlesampleStencilFinalLayout;
+       }
+
+       if (renderPassNo != 0)
+       {
+               multisampleStencilFinalLayout.stencilInitialLayout = stencilLayout.stencilLayout;
+               singlesampleStencilFinalLayout.stencilInitialLayout = stencilLayout.stencilLayout;
+       }
+
+       if (renderPassNo != m_numRenderPasses - 1)
+       {
+               finalLayout = layout;
+               multisampleStencilFinalLayout.stencilFinalLayout = layout;
+               singlesampleStencilFinalLayout.stencilFinalLayout = layout;
        }
 
        const AttachmentDescription2 multisampleAttachment              // VkAttachmentDescription2
        (
                                                                                                                        // VkStructureType                                      sType;
-               attachmentDescriptionStencil,                                           // const void*                                          pNext;
+               multisampleAttachmentDescriptionStencil,                        // const void*                                          pNext;
                0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
                m_config.format,                                                                        // VkFormat                                                     format;
                samples,                                                                                        // VkSampleCountFlagBits                        samples;
-               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
-               VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          storeOp;
-               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           stencilLoadOp;
-               VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
-               VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout                                        initialLayout;
+               (renderPassNo == 0) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,         // VkAttachmentLoadOp                           loadOp;
+               VK_ATTACHMENT_STORE_OP_STORE,
+               (renderPassNo == 0) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,         // VkAttachmentLoadOp                           stencilLoadOp;
+               VK_ATTACHMENT_STORE_OP_STORE,
+               (renderPassNo == 0) ? VK_IMAGE_LAYOUT_UNDEFINED : layout,                                                       // VkImageLayout                                        initialLayout;
                finalLayout                                                                                     // VkImageLayout                                        finalLayout;
        );
        const AttachmentReference2 multisampleAttachmentRef             // VkAttachmentReference2
@@ -506,17 +520,26 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
                attachmentRefStencil,                                                           // const void*                                          pNext;
                0u,                                                                                                     // deUint32                                                     attachment;
                layout,                                                                                         // VkImageLayout                                        layout;
-               0u                                                                                                      // VkImageAspectFlags                           aspectMask;
+               m_config.aspectFlag                                                                     // VkImageAspectFlags                           aspectMask;
        );
 
-       const vk::VkImageLayout         singleSampleInitialLayout = (m_config.unusedResolve ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED);
+       vk::VkImageLayout               singleSampleInitialLayout = (m_config.unusedResolve ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED);
+       if (renderPassNo != 0)
+               singleSampleInitialLayout = layout;
+       if (m_config.separateDepthStencilLayouts && m_config.verifyBuffer == VB_STENCIL)
+               singlesampleStencilFinalLayout.stencilInitialLayout = singleSampleInitialLayout;
+
+       const tcu::TextureFormat                        format                  (mapVkFormat(vkformat));
+       VkImageAspectFlags aspectFlags =
+               ((tcu::hasDepthComponent(format.order)          ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_DEPTH_BIT)    : 0u) |
+                (tcu::hasStencilComponent(format.order)        ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_STENCIL_BIT)  : 0u));
 
        const AttachmentDescription2 singlesampleAttachment             // VkAttachmentDescription2
        (
                                                                                                                        // VkStructureType                                      sType;
-               attachmentDescriptionStencil,                                           // const void*                                          pNext;
+               singlesampleAttachmentDescriptionStencil,                       // const void*                                          pNext;
                0u,                                                                                                     // VkAttachmentDescriptionFlags         flags;
-               m_config.format,                                                                        // VkFormat                                                     format;
+               vkformat,                                                                                       // VkFormat                                                     format;
                VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                        samples;
                VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
                VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
@@ -528,10 +551,10 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
        AttachmentReference2 singlesampleAttachmentRef                  // VkAttachmentReference2
        (
                                                                                                                                // VkStructureType                                      sType;
-               DE_NULL,                                                                                                // const void*                                          pNext;
-               (m_config.unusedResolve ? VK_ATTACHMENT_UNUSED : 1u),   // deUint32                                                     attachment;
+               attachmentRefStencil,                                                                   // const void*                                          pNext;
+               ((m_config.unusedResolve || renderPassNo != m_numRenderPasses - 1) ? VK_ATTACHMENT_UNUSED : 1u),        // deUint32                                                     attachment;
                layout,                                                                                                 // VkImageLayout                                        layout;
-               0u                                                                                                              // VkImageAspectFlags                           aspectMask;
+               aspectFlags                                                                                             // VkImageAspectFlags                           aspectMask;
        );
 
        std::vector<AttachmentDescription2> attachments;
@@ -550,7 +573,7 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
        const SubpassDescription2 subpass                                       // VkSubpassDescription2
        (
                                                                                                                // VkStructureType                                              sType;
-               &dsResolveDescription,                                                  // const void*                                                  pNext;
+               renderPassNo == m_numRenderPasses - 1 ? &dsResolveDescription : DE_NULL,        // const void*                                                  pNext;
                (VkSubpassDescriptionFlags)0,                                   // VkSubpassDescriptionFlags                    flags;
                VK_PIPELINE_BIND_POINT_GRAPHICS,                                // VkPipelineBindPoint                                  pipelineBindPoint;
                0u,                                                                                             // deUint32                                                             viewMask;
@@ -582,6 +605,31 @@ Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void)
        return renderPassCreator.createRenderPass(m_vkd, m_device);
 }
 
+// Checks format support.
+// Note: we need the context because this is called from the constructor only after m_config has been set.
+bool DepthStencilResolveTest::isSupportedFormat (Context& context, VkFormat format) const
+{
+       const VkImageUsageFlags usage   = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
+                                                                       | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+                                                                       | (m_config.unusedResolve ? VK_IMAGE_USAGE_TRANSFER_DST_BIT : static_cast<vk::VkImageUsageFlagBits>(0u));
+       VkImageFormatProperties props;
+
+       const auto&     vki                             = context.getInstanceInterface();
+       const auto      physicalDevice  = context.getPhysicalDevice();
+       const auto      formatCheck             = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, 0u, &props);
+
+       return (formatCheck == VK_SUCCESS);
+}
+
+Move<VkRenderPass> DepthStencilResolveTest::createRenderPassCompatible (void)
+{
+       // Early exit if we are not testing compatibility.
+       if (! m_config.compatibleFormat)
+               return {};
+
+       return createRenderPass(m_config.compatibleFormat.get(), 0);
+}
+
 Move<VkFramebuffer> DepthStencilResolveTest::createFramebuffer (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView)
 {
        std::vector<VkImageView> attachments;
@@ -639,7 +687,7 @@ Move<VkPipelineLayout> DepthStencilResolveTest::createRenderPipelineLayout (void
        return vk::createPipelineLayout(m_vkd, m_device, &createInfo);
 }
 
-Move<VkPipeline> DepthStencilResolveTest::createRenderPipeline (VkRenderPass renderPass, VkPipelineLayout renderPipelineLayout)
+Move<VkPipeline> DepthStencilResolveTest::createRenderPipeline (VkRenderPass renderPass, deUint32 renderPassNo, VkPipelineLayout renderPipelineLayout)
 {
        const bool testingStencil = (m_config.verifyBuffer == VB_STENCIL);
        const vk::BinaryCollection& binaryCollection = m_context.getBinaryCollection();
@@ -663,6 +711,9 @@ Move<VkPipeline> DepthStencilResolveTest::createRenderPipeline (VkRenderPass ren
        const tcu::UVec2                                view            (m_config.width, m_config.height);
        const std::vector<VkViewport>   viewports       (1, makeViewport(view));
        const std::vector<VkRect2D>             scissors        (1, m_config.renderArea);
+       const VkSampleMask samplemask[2] = {
+               renderPassNo < 32 ? (1u << renderPassNo) : 0,
+               renderPassNo < 32 ? 0 : (1u << (renderPassNo - 32)) };
 
        const VkPipelineMultisampleStateCreateInfo multisampleState =
        {
@@ -673,7 +724,7 @@ Move<VkPipeline> DepthStencilResolveTest::createRenderPipeline (VkRenderPass ren
                sampleCountBitFromSampleCount(m_config.sampleCount),
                VK_FALSE,
                0.0f,
-               DE_NULL,
+               (m_config.sampleMask) ? &samplemask[0] : DE_NULL,
                VK_FALSE,
                VK_FALSE,
        };
@@ -776,61 +827,152 @@ void DepthStencilResolveTest::submit (void)
 {
        const DeviceInterface&                                          vkd                                     (m_context.getDeviceInterface());
        const VkDevice                                                          device                          (m_context.getDevice());
-       const Unique<VkCommandBuffer>                           commandBuffer           (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
-       const RenderpassSubpass2::SubpassBeginInfo      subpassBeginInfo        (DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
-       const RenderpassSubpass2::SubpassEndInfo        subpassEndInfo          (DE_NULL);
-
-       beginCommandBuffer(vkd, *commandBuffer);
 
+       // When the depth/stencil resolve attachment is unused, it needs to be cleared outside
+       // the render pass so it has the expected values.
+       if (m_config.unusedResolve)
        {
-               VkClearValue clearValues[2];
-               clearValues[0].depthStencil = m_config.clearValue;
-               clearValues[1].depthStencil = m_config.clearValue;
+               const tcu::TextureFormat                        format                  (mapVkFormat(m_config.format));
+               const Unique<VkCommandBuffer>           commandBuffer   (allocateCommandBuffer(m_vkd, m_device, *m_commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+               const vk::VkImageSubresourceRange       imageRange              =
+               {
+                       ((tcu::hasDepthComponent(format.order)          ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_DEPTH_BIT)    : 0u) |
+                        (tcu::hasStencilComponent(format.order)        ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_STENCIL_BIT)  : 0u)),
+                       0u,
+                       VK_REMAINING_MIP_LEVELS,
+                       0u,
+                       VK_REMAINING_ARRAY_LAYERS,
+               };
+               const vk::VkImageMemoryBarrier          preBarrier              =
+               {
+                       vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                       nullptr,
+
+                       // src and dst access masks.
+                       0,
+                       vk::VK_ACCESS_TRANSFER_WRITE_BIT,
+
+                       // old and new layouts.
+                       vk::VK_IMAGE_LAYOUT_UNDEFINED,
+                       vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+
+                       VK_QUEUE_FAMILY_IGNORED,
+                       VK_QUEUE_FAMILY_IGNORED,
 
-               const VkRenderPassBeginInfo beginInfo =
+                       **m_singlesampleImage,
+                       imageRange,
+               };
+               const vk::VkImageMemoryBarrier          postBarrier             =
                {
-                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                       DE_NULL,
+                       vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                       nullptr,
 
-                       *m_renderPass,
-                       *m_framebuffer,
+                       // src and dst access masks.
+                       vk::VK_ACCESS_TRANSFER_WRITE_BIT,
+                       0,
 
-                       {
-                               { 0u, 0u },
-                               { m_config.width, m_config.height }
-                       },
+                       // old and new layouts.
+                       vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                       vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 
-                       2u,
-                       clearValues
+                       VK_QUEUE_FAMILY_IGNORED,
+                       VK_QUEUE_FAMILY_IGNORED,
+
+                       **m_singlesampleImage,
+                       imageRange,
                };
-               RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
+
+               vk::beginCommandBuffer(m_vkd, commandBuffer.get());
+               m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preBarrier);
+               m_vkd.cmdClearDepthStencilImage(commandBuffer.get(), **m_singlesampleImage, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_config.clearValue, 1u, &imageRange);
+               m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &postBarrier);
+               vk::endCommandBuffer(m_vkd, commandBuffer.get());
+
+               vk::submitCommandsAndWait(m_vkd, m_device, m_context.getUniversalQueue(), commandBuffer.get());
        }
 
-       // Render
+       const Unique<VkCommandBuffer>                           commandBuffer(allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+       const RenderpassSubpass2::SubpassBeginInfo      subpassBeginInfo(DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
+       const RenderpassSubpass2::SubpassEndInfo        subpassEndInfo(DE_NULL);
+
+       beginCommandBuffer(vkd, *commandBuffer);
        bool testingDepth = (m_config.verifyBuffer == VB_DEPTH);
        if (testingDepth)
        {
-               vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline);
+               {
+                       VkClearValue clearValues[2];
+                       clearValues[0].depthStencil = m_config.clearValue;
+                       clearValues[1].depthStencil = m_config.clearValue;
+
+                       const VkRenderPassBeginInfo beginInfo =
+                       {
+                               VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                               DE_NULL,
+
+                                       (m_config.compatibleFormat ? *m_renderPassCompatible : *m_renderPass[0]),
+                               *m_framebuffer,
+
+                               {
+                                       { 0u, 0u },
+                                       { m_config.width, m_config.height }
+                               },
+
+                               2u,
+                               clearValues
+                       };
+                       RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
+               }
+
+               // Render
+               vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline[0]);
                vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
+               RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
        }
        else
        {
-               // For stencil we can set reference value for just one sample at a time
-               // so we need to do as many passes as there are samples, first half
-               // of samples is initialized with 1 and second half with 255
-               const deUint32 halfOfSamples = m_config.sampleCount >> 1;
-               for (deUint32 renderPass = 0 ; renderPass < m_config.sampleCount ; renderPass++)
+               // Stencil
+               for (deUint32 i = 0; i < m_config.sampleCount; i++)
                {
-                       deUint32 stencilReference = 1 + 254 * (renderPass >= halfOfSamples);
-                       vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline);
-                       vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(renderPass), &renderPass);
+                       if (i == 0 || m_config.sampleMask)
+                       {
+                               VkClearValue clearValues[2];
+                               clearValues[0].depthStencil = m_config.clearValue;
+                               clearValues[1].depthStencil = m_config.clearValue;
+
+                               const VkRenderPassBeginInfo beginInfo =
+                               {
+                                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                       DE_NULL,
+
+                                       (m_config.compatibleFormat ? *m_renderPassCompatible : *m_renderPass[i]),
+                                       *m_framebuffer,
+
+                                       {
+                                               { 0u, 0u },
+                                               { m_config.width, m_config.height }
+                                       },
+
+                                       2u,
+                                       clearValues
+                               };
+                               vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, 0, 0, 0, 0, 0);
+                               RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
+                       }
+                       // For stencil we can set reference value for just one sample at a time
+                       // so we need to do as many passes as there are samples, first half
+                       // of samples is initialized with 1 and second half with 255
+                       const deUint32 halfOfSamples = m_config.sampleCount >> 1;
+
+                       deUint32 stencilReference = 1 + 254 * (i >= halfOfSamples);
+                       vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline[m_config.sampleMask ? i : 0]);
+                       vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(i), &i);
                        vkd.cmdSetStencilReference(*commandBuffer, VK_STENCIL_FRONT_AND_BACK, stencilReference);
                        vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
+                       if (i == m_config.sampleCount - 1 || m_config.sampleMask)
+                               RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
                }
        }
 
-       RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
-
        // Memory barriers between rendering and copying
        {
                const VkImageMemoryBarrier barrier =
@@ -838,7 +980,8 @@ void DepthStencilResolveTest::submit (void)
                        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
                        DE_NULL,
 
-                       VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                       // Note: as per the spec, depth/stencil *resolve* operations are synchronized using the color attachment write access.
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
                        VK_ACCESS_TRANSFER_READ_BIT,
 
                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
@@ -1137,19 +1280,33 @@ struct Programs
                }
                else
                {
-                       dst.glslSources.add("quad-frag") << glu::FragmentSource(
-                               "#version 450\n"
-                               "precision highp float;\n"
-                               "precision highp int;\n"
-                               "layout(push_constant) uniform PushConstant {\n"
-                               "  highp int sampleID;\n"
-                               "} pushConstants;\n"
-                               "void main (void)\n"
-                               "{\n"
-                               "  if(gl_SampleID != pushConstants.sampleID)\n"
-                               "    discard;\n"
-                               "  gl_FragDepth = 0.5;\n"
-                               "}\n");
+                       if (config.sampleMask)
+                       {
+                               dst.glslSources.add("quad-frag") << glu::FragmentSource(
+                                       "#version 450\n"
+                                       "precision highp float;\n"
+                                       "precision highp int;\n"
+                                       "void main (void)\n"
+                                       "{\n"
+                                       "  gl_FragDepth = 0.5;\n"
+                                       "}\n");
+                       }
+                       else
+                       {
+                               dst.glslSources.add("quad-frag") << glu::FragmentSource(
+                                       "#version 450\n"
+                                       "precision highp float;\n"
+                                       "precision highp int;\n"
+                                       "layout(push_constant) uniform PushConstant {\n"
+                                       "  highp int sampleID;\n"
+                                       "} pushConstants;\n"
+                                       "void main (void)\n"
+                                       "{\n"
+                                       "  if(gl_SampleID != pushConstants.sampleID)\n"
+                                       "    discard;\n"
+                                       "  gl_FragDepth = 0.5;\n"
+                                       "}\n");
+                       }
                }
        }
 };
@@ -1299,6 +1456,8 @@ void initTests (tcu::TestCaseGroup* group)
                { 255u,                 255u,   255u,   255u,   255u,   255u }, // RESOLVE_MODE_MAX_BIT
        };
 
+       const DepthCompatibilityManager compatManager;
+
        tcu::TestContext& testCtx(group->getTestContext());
 
        // Misc tests.
@@ -1407,8 +1566,24 @@ void initTests (tcu::TestCaseGroup* group)
                                                                                0u,
                                                                                useSeparateDepthStencilLayouts,
                                                                                unusedResolve,
+                                                                               tcu::nothing<VkFormat>(),
+                                                                               false
                                                                        };
                                                                        formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
+
+                                                                       if (sampleCountNdx == 0 && imageDataNdx == 0)
+                                                                       {
+                                                                               const auto compatibleFormat = compatManager.getAlternativeFormat(format);
+
+                                                                               if (compatibleFormat != VK_FORMAT_UNDEFINED)
+                                                                               {
+                                                                                       std::string     compatibilityTestName                   = "compatibility_" + name;
+                                                                                       TestConfig compatibilityTestConfig                      = testConfig;
+                                                                                       compatibilityTestConfig.compatibleFormat        = tcu::just(compatibleFormat);
+
+                                                                                       formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, compatibilityTestName.c_str(), compatibilityTestName.c_str(), compatibilityTestConfig));
+                                                                               }
+                                                                       }
                                                                }
                                                                if (hasStencil)
                                                                {
@@ -1435,8 +1610,30 @@ void initTests (tcu::TestCaseGroup* group)
                                                                                expectedValue,
                                                                                useSeparateDepthStencilLayouts,
                                                                                unusedResolve,
+                                                                               tcu::nothing<VkFormat>(),
+                                                                               false
                                                                        };
                                                                        formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
+
+                                                                       if (dResolve.flag == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT)
+                                                                       {
+                                                                               std::string samplemaskTestName = name + "_samplemask";
+                                                                               TestConfig samplemaskTestConfig = testConfig;
+                                                                               samplemaskTestConfig.sampleMask = true;
+                                                                               formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, samplemaskTestName.c_str(), samplemaskTestName.c_str(), samplemaskTestConfig));
+                                                                       }
+
+                                                                       // All formats with stencil and depth aspects have incompatible formats and sizes in the depth
+                                                                       // aspect, so their only alternative is the VK_FORMAT_S8_UINT format. Finally, that stencil-only
+                                                                       // format has no compatible formats that can be used.
+                                                                       if (sampleCountNdx == 0 && imageDataNdx == 0 && hasDepth)
+                                                                       {
+                                                                               std::string     compatibilityTestName                   = "compatibility_" + name;
+                                                                               TestConfig compatibilityTestConfig                      = testConfig;
+                                                                               compatibilityTestConfig.compatibleFormat        = tcu::just(VK_FORMAT_S8_UINT);
+
+                                                                               formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, compatibilityTestName.c_str(), compatibilityTestName.c_str(), compatibilityTestConfig));
+                                                                       }
                                                                }
                                                        }
                                                }
@@ -1524,6 +1721,8 @@ void initTests (tcu::TestCaseGroup* group)
                                                                        0u,
                                                                        useSeparateDepthStencilLayouts,
                                                                        unusedResolve,
+                                                                       tcu::nothing<VkFormat>(),
+                                                                       false
                                                                };
                                                                formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
                                                        }
@@ -1556,6 +1755,8 @@ void initTests (tcu::TestCaseGroup* group)
                                                                        expectedValue,
                                                                        useSeparateDepthStencilLayouts,
                                                                        unusedResolve,
+                                                                       tcu::nothing<VkFormat>(),
+                                                                       false
                                                                };
                                                                formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
                                                        }