Add more test related to early fragment tests
authorSamuel Iglesias Gonsálvez <siglesias@igalia.com>
Tue, 15 Jun 2021 11:19:12 +0000 (13:19 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Thu, 22 Jul 2021 06:53:12 +0000 (06:53 +0000)
- Added tests for EarlyFragmentTest followed by a shader which
  discards. Then check that depth buffer is updated but the color
  buffer and other outputs are not.

- Added tests that write to gl_SampleMask and checked that do not affect
  the depth values written to the depth buffer.

Components: Vulkan
VK-GL-CTS issue: 2968

Added tests:

   dEQP-VK.fragment_operations.early_fragment.discard*
   dEQP-VK.fragment_operations.early_fragment.samplemask*

Signed-off-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
Change-Id: I4a0bd49ab9319747e8c92aaa26f64a4e077fa8a5

android/cts/master/vk-master-2021-03-01.txt
android/cts/master/vk-master/fragment-operations.txt
external/vulkancts/modules/vulkan/fragment_ops/vktFragmentOperationsEarlyFragmentTests.cpp
external/vulkancts/mustpass/master/vk-default/fragment-operations.txt

index bc4ac54..0b1d07b 100644 (file)
@@ -6,6 +6,7 @@ vk-master-2021-03-01/descriptor-indexing.txt
 vk-master-2021-03-01/draw.txt
 vk-master-2021-03-01/drm-format-modifiers.txt
 vk-master-2021-03-01/dynamic-state.txt
+vk-master-2021-03-01/fragment-operations.txt
 vk-master-2021-03-01/fragment-shading-rate.txt
 vk-master-2021-03-01/geometry.txt
 vk-master-2021-03-01/glsl.txt
index ab0c7b8..1491230 100644 (file)
@@ -33,3 +33,15 @@ dEQP-VK.fragment_operations.early_fragment.no_early_fragment_tests_depth_no_atta
 dEQP-VK.fragment_operations.early_fragment.no_early_fragment_tests_stencil_no_attachment
 dEQP-VK.fragment_operations.early_fragment.early_fragment_tests_depth_no_attachment
 dEQP-VK.fragment_operations.early_fragment.early_fragment_tests_stencil_no_attachment
+dEQP-VK.fragment_operations.early_fragment.discard_no_early_fragment_tests_depth
+dEQP-VK.fragment_operations.early_fragment.discard_no_early_fragment_tests_stencil
+dEQP-VK.fragment_operations.early_fragment.discard_early_fragment_tests_depth
+dEQP-VK.fragment_operations.early_fragment.discard_early_fragment_tests_stencil
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_2
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_2
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_4
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_4
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_8
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_8
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_16
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_16
index 5e8aef3..351a1a2 100644 (file)
 #include "vkObjUtil.hpp"
 
 #include "tcuTestLog.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuTextureUtil.hpp"
 
 #include "deUniquePtr.hpp"
 #include "deStringUtil.hpp"
+#include "deMath.h"
 
 #include <string>
 
@@ -98,18 +101,20 @@ Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&      vk,
                                                                           const VkShaderModule         fragmentModule,
                                                                           const tcu::IVec2&            renderSize,
                                                                           const bool                           enableDepthTest,
-                                                                          const bool                           enableStencilTest)
+                                                                          const bool                           enableStencilTest,
+                                                                          const VkStencilOp            stencilFailOp = VK_STENCIL_OP_KEEP,
+                                                                          const VkStencilOp            stencilPassOp = VK_STENCIL_OP_KEEP)
 {
        const std::vector<VkViewport>                   viewports                                       (1, makeViewport(renderSize));
        const std::vector<VkRect2D>                             scissors                                        (1, makeRect2D(renderSize));
 
        const VkStencilOpState                                  stencilOpState                          = makeStencilOpState(
-               VK_STENCIL_OP_KEEP,             // stencil fail
-               VK_STENCIL_OP_KEEP,             // depth & stencil pass
+               stencilFailOp,                  // stencil fail
+           stencilPassOp,                      // depth & stencil pass
                VK_STENCIL_OP_KEEP,             // depth only fail
                VK_COMPARE_OP_EQUAL,    // compare op
-               1u,                                             // compare mask
-               1u,                                             // write mask
+               0x3,                                    // compare mask
+               0xf,                                    // write mask
                1u);                                    // reference
 
        VkPipelineDepthStencilStateCreateInfo   depthStencilStateCreateInfo     =
@@ -510,30 +515,1168 @@ void EarlyFragmentTest::checkSupport (Context& context) const
        context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
 }
 
+class EarlyFragmentDiscardTestInstance : public EarlyFragmentTestInstance
+{
+public:
+                                                       EarlyFragmentDiscardTestInstance        (Context& context, const deUint32 flags);
+
+       tcu::TestStatus                 iterate                                                         (void);
+
+private:
+       tcu::TextureLevel       generateReferenceColorImage                             (const tcu::TextureFormat format, const tcu::IVec2& renderSize);
+       enum TestMode
+       {
+               MODE_INVALID,
+               MODE_DEPTH,
+               MODE_STENCIL,
+       };
+
+       const TestMode                  m_testMode;
+       const bool                              m_useTestAttachment;
+       const bool                              m_useEarlyTests;
+};
+
+EarlyFragmentDiscardTestInstance::EarlyFragmentDiscardTestInstance (Context& context, const deUint32 flags)
+       : EarlyFragmentTestInstance                     (context, flags)
+       , m_testMode                    (flags & FLAG_TEST_DEPTH   ? MODE_DEPTH :
+                                                        flags & FLAG_TEST_STENCIL ? MODE_STENCIL : MODE_INVALID)
+       , m_useTestAttachment   ((flags & FLAG_DONT_USE_TEST_ATTACHMENT) == 0)
+       , m_useEarlyTests               ((flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0)
+{
+       DE_ASSERT(m_testMode != MODE_INVALID);
+}
+
+tcu::TextureLevel EarlyFragmentDiscardTestInstance::generateReferenceColorImage(const tcu::TextureFormat format, const tcu::IVec2 &renderSize)
+{
+       tcu::TextureLevel       image(format, renderSize.x(), renderSize.y());
+       const tcu::Vec4         clearColor      = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+
+       tcu::clear(image.getAccess(), clearColor);
+
+       return image;
+}
+
+tcu::TestStatus EarlyFragmentDiscardTestInstance::iterate (void)
+{
+       const DeviceInterface&          vk                                      = m_context.getDeviceInterface();
+       const InstanceInterface&        vki                                     = m_context.getInstanceInterface();
+       const VkDevice                          device                          = m_context.getDevice();
+       const VkPhysicalDevice          physDevice                      = m_context.getPhysicalDevice();
+       const VkQueue                           queue                           = m_context.getUniversalQueue();
+       const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       Allocator&                                      allocator                       = m_context.getDefaultAllocator();
+
+       DE_ASSERT(m_useTestAttachment);
+
+       // Color attachment
+       const tcu::IVec2                                renderSize                              = tcu::IVec2(32, 32);
+       const VkFormat                                  colorFormat                             = VK_FORMAT_R8G8B8A8_UNORM;
+       const VkImageSubresourceRange   colorSubresourceRange   = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const Unique<VkImage>                   colorImage                              (makeImage(vk, device, makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
+       const UniquePtr<Allocation>             colorImageAlloc                 (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               colorImageView                  (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
+
+       // Test attachment (depth or stencil)
+       static const VkFormat stencilFormats[] =
+       {
+               // One of the following formats must be supported, as per spec requirement.
+               VK_FORMAT_S8_UINT,
+               VK_FORMAT_D16_UNORM_S8_UINT,
+               VK_FORMAT_D24_UNORM_S8_UINT,
+               VK_FORMAT_D32_SFLOAT_S8_UINT,
+       };
+
+       const VkFormat depthStencilFormat = (m_testMode == MODE_STENCIL ? pickSupportedDepthStencilFormat(vki, physDevice, DE_LENGTH_OF_ARRAY(stencilFormats), stencilFormats)
+                                                                                : VK_FORMAT_D16_UNORM);                // spec requires this format to be supported
+
+       if (depthStencilFormat == VK_FORMAT_UNDEFINED)
+               return tcu::TestStatus::fail("Required depth/stencil format not supported");
+
+       m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format " << getFormatName(depthStencilFormat) << tcu::TestLog::EndMessage;
+
+       const VkImageSubresourceRange   testSubresourceRange    = makeImageSubresourceRange(getImageAspectFlags(depthStencilFormat), 0u, 1u, 0u, 1u);
+       const Unique<VkImage>                   testImage                               (makeImage(vk, device, makeImageCreateInfo(renderSize, depthStencilFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
+       const UniquePtr<Allocation>             testImageAlloc                  (bindImage(vk, device, allocator, *testImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               testImageView                   (makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, depthStencilFormat, testSubresourceRange));
+       const VkImageView                               attachmentImages[]              = { *colorImageView, *testImageView };
+       const deUint32                                  numUsedAttachmentImages = DE_LENGTH_OF_ARRAY(attachmentImages);
+
+       // Vertex buffer
+
+       const deUint32                                  numVertices                             = 6;
+       const VkDeviceSize                              vertexBufferSizeBytes   = sizeof(tcu::Vec4) * numVertices;
+       const Unique<VkBuffer>                  vertexBuffer                    (makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
+       const UniquePtr<Allocation>             vertexBufferAlloc               (bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
+
+       {
+               tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
+
+               pVertices[0] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
+               pVertices[1] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
+               pVertices[2] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
+
+               pVertices[3] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
+               pVertices[4] = tcu::Vec4( 1.0f,  1.0f,  1.0f,  1.0f);
+               pVertices[5] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
+
+               flushAlloc(vk, device, *vertexBufferAlloc);
+               // No barrier needed, flushed memory is automatically visible
+       }
+
+       // Result buffer
+
+       const VkDeviceSize                              resultBufferSizeBytes   = sizeof(deUint32);
+       const Unique<VkBuffer>                  resultBuffer                    (makeBuffer(vk, device, resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
+       const UniquePtr<Allocation>             resultBufferAlloc               (bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
+
+       {
+               deUint32* const pData = static_cast<deUint32*>(resultBufferAlloc->getHostPtr());
+
+               *pData = 0;
+               flushAlloc(vk, device, *resultBufferAlloc);
+       }
+
+       // Render result buffer (to retrieve color attachment contents)
+
+       const VkDeviceSize                              colorBufferSizeBytes    = tcu::getPixelSize(mapVkFormat(colorFormat)) * renderSize.x() * renderSize.y();
+       const Unique<VkBuffer>                  colorBuffer                             (makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+       const UniquePtr<Allocation>             colorBufferAlloc                (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
+
+       // Depth stencil result buffer (to retrieve depth-stencil attachment contents)
+
+       const VkDeviceSize                              dsBufferSizeBytes       = tcu::getPixelSize(mapVkFormat(depthStencilFormat)) * renderSize.x() * renderSize.y();
+       const Unique<VkBuffer>                  dsBuffer                        (makeBuffer(vk, device, dsBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+       const UniquePtr<Allocation>             dsBufferAlloc           (bindBuffer(vk, device, allocator, *dsBuffer, MemoryRequirement::HostVisible));
+
+       // Descriptors
+
+       const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
+               .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
+               .build(vk, device));
+
+       const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
+               .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+               .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
+
+       const Unique<VkDescriptorSet> descriptorSet                              (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
+       const VkDescriptorBufferInfo  resultBufferDescriptorInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
+
+       DescriptorSetUpdateBuilder()
+               .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferDescriptorInfo)
+               .update(vk, device);
+
+       // Pipeline
+
+       const Unique<VkShaderModule>    vertexModule  (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
+       const Unique<VkShaderModule>    fragmentModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
+       const Unique<VkRenderPass>              renderPass        (makeRenderPass(vk, device, colorFormat, m_useTestAttachment, depthStencilFormat));
+       const Unique<VkFramebuffer>             framebuffer       (makeFramebuffer(vk, device, *renderPass, numUsedAttachmentImages, attachmentImages, renderSize.x(), renderSize.y()));
+       const Unique<VkPipelineLayout>  pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
+       const Unique<VkPipeline>                pipeline          (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, renderSize,
+                                                                                                                                               (m_testMode == MODE_DEPTH), (m_testMode == MODE_STENCIL),
+                                                                                                                                               VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP));
+       const Unique<VkCommandPool>             cmdPool           (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer         (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+
+       // Draw commands
+       {
+               const VkRect2D renderArea = {
+                       makeOffset2D(0, 0),
+                       makeExtent2D(renderSize.x(), renderSize.y()),
+               };
+               const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+               const VkDeviceSize vertexBufferOffset = 0ull;
+
+               beginCommandBuffer(vk, *cmdBuffer);
+
+               {
+                       const VkImageMemoryBarrier barriers[] = {
+                               makeImageMemoryBarrier(
+                                       0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                                       *colorImage, colorSubresourceRange),
+                               makeImageMemoryBarrier(
+                                       0u, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+                                       *testImage, testSubresourceRange),
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
+               }
+
+               // Will clear the attachments with specified depth and stencil values.
+               beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor, 0.5f, 3u);
+
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+               vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
+               vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
+
+               // Mask half of the attachment image with value that will pass the stencil test.
+               if (m_testMode == MODE_STENCIL)
+                       commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(0, 0), makeExtent2D(renderSize.x()/2, renderSize.y()), 1u);
+
+               vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
+               endRenderPass(vk, *cmdBuffer);
+
+               copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, renderSize, VK_ACCESS_SHADER_WRITE_BIT);
+               VkImageAspectFlags dsAspect = m_testMode == MODE_DEPTH ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
+               copyImageToBuffer(vk, *cmdBuffer, *testImage, *dsBuffer, renderSize, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, 1u, dsAspect, dsAspect);
+
+               endCommandBuffer(vk, *cmdBuffer);
+               submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+       }
+
+       // Verify color output
+       {
+               invalidateAlloc(vk, device, *colorBufferAlloc);
+
+               const tcu::ConstPixelBufferAccess       imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc->getHostPtr());
+               const tcu::TextureLevel                         referenceImage  = generateReferenceColorImage(mapVkFormat(colorFormat), renderSize);
+               if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", referenceImage.getAccess(), imagePixelAccess, tcu::Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
+                       printf("Rendered color image is not correct");
+       }
+
+       // Verify depth-stencil output
+       {
+               invalidateAlloc(vk, device, *dsBufferAlloc);
+               tcu::TextureFormat format = mapVkFormat(depthStencilFormat);
+               const tcu::ConstPixelBufferAccess       dsPixelAccess (format, renderSize.x(), renderSize.y(), 1, dsBufferAlloc->getHostPtr());
+
+               for(int z = 0; z < dsPixelAccess.getDepth(); z++)
+               for(int y = 0; y < dsPixelAccess.getHeight(); y++)
+               for(int x = 0; x < dsPixelAccess.getWidth(); x++)
+               {
+                       float   depthValue              = (m_testMode == MODE_DEPTH) ? dsPixelAccess.getPixDepth(x, y, z) : 0.0f;
+                       int             stencilValue    = (m_testMode == MODE_STENCIL) ? dsPixelAccess.getPixStencil(x, y, z) : 0;
+
+                       // Depth test should write to the depth buffer even when there is a discard in the fragment shader,
+                       // when early fragment tests are enabled.
+                       if (m_testMode == MODE_DEPTH)
+                       {
+                               if (m_useEarlyTests && ((x + y) < 31) && depthValue >= 0.5f)
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered depth value [ "<< x << ", " << y << ", " << z << "] is not correct: " << depthValue << " >= 0.5f";
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                               // When early fragment tests are disabled, the depth test happens after the fragment shader, but as we are discarding
+                               // all fragments, the stored value in the depth buffer should be the clear one (0.5f).
+                               if (!m_useEarlyTests && deAbs(depthValue - 0.5f) > 0.01f)
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered depth value [ "<< x << ", " << y << ", " << z << "] is not correct: " << depthValue << " != 0.5f";
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                       }
+
+                       if (m_testMode == MODE_STENCIL)
+                       {
+                               if (m_useEarlyTests && ((x < 16 && stencilValue != 2u) || (x >= 16 && stencilValue != 4u)))
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered stencil value [ "<< x << ", " << y << ", " << z << "] is not correct: " << stencilValue << " != ";
+                                       error << (x < 16 ? 2u : 4u);
+                                       TCU_FAIL(error.str().c_str());
+                               }
+
+                               if (!m_useEarlyTests && ((x < 16 && stencilValue != 1u) || (x >= 16 && stencilValue != 3u)))
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered stencil value [ "<< x << ", " << y << ", " << z << "] is not correct: " << stencilValue << " != ";
+                                       error << (x < 16 ? 1u : 3u);
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                       }
+               }
+       }
+
+       // Verify we process all the fragments
+       {
+               invalidateAlloc(vk, device, *resultBufferAlloc);
+
+               const int  actualCounter           = *static_cast<deInt32*>(resultBufferAlloc->getHostPtr());
+               const bool expectPartialResult = m_useEarlyTests;
+               const int  expectedCounter         = expectPartialResult ? renderSize.x() * renderSize.y() / 2 : renderSize.x() * renderSize.y();
+               const int  tolerance               = expectPartialResult ? de::max(renderSize.x(), renderSize.y()) * 3  : 0;
+               const int  expectedMin         = de::max(0, expectedCounter - tolerance);
+               const int  expectedMax             = expectedCounter + tolerance;
+
+               tcu::TestLog& log = m_context.getTestContext().getLog();
+               log << tcu::TestLog::Message << "Expected value"
+                       << (expectPartialResult ? " in range: [" + de::toString(expectedMin) + ", " + de::toString(expectedMax) + "]" : ": " + de::toString(expectedCounter))
+                       << tcu::TestLog::EndMessage;
+               log << tcu::TestLog::Message << "Result value: " << de::toString(actualCounter) << tcu::TestLog::EndMessage;
+
+               if (expectedMin <= actualCounter && actualCounter <= expectedMax)
+                       return tcu::TestStatus::pass("Success");
+               else
+                       return tcu::TestStatus::fail("Value out of range");
+       }
+}
+
+class EarlyFragmentDiscardTest : public EarlyFragmentTest
+{
+public:
+                                               EarlyFragmentDiscardTest        (tcu::TestContext&              testCtx,
+                                                                                                        const std::string              name,
+                                                                                                        const deUint32                 flags);
+
+       void                            initPrograms                            (SourceCollections&             programCollection) const;
+       TestInstance*           createInstance                          (Context&                               context) const;
+
+private:
+       const deUint32          m_flags;
+};
+
+EarlyFragmentDiscardTest::EarlyFragmentDiscardTest (tcu::TestContext& testCtx, const std::string name, const deUint32 flags)
+       : EarlyFragmentTest     (testCtx, name, flags)
+       , m_flags (flags)
+{
+}
+
+TestInstance* EarlyFragmentDiscardTest::createInstance (Context& context) const
+{
+       return new EarlyFragmentDiscardTestInstance(context, m_flags);
+}
+
+void EarlyFragmentDiscardTest::initPrograms(SourceCollections &programCollection) const
+{
+       // Vertex
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
+                       << "\n"
+                       << "layout(location = 0) in highp vec4 position;\n"
+                       << "\n"
+                       << "out gl_PerVertex {\n"
+                       << "   vec4 gl_Position;\n"
+                       << "};\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_Position = position;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment
+       {
+               const bool useEarlyTests = (m_flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0;
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
+                       << "\n"
+                       << (useEarlyTests ? "layout(early_fragment_tests) in;\n" : "")
+                       << "layout(location = 0) out highp vec4 fragColor;\n"
+                       << "\n"
+                       << "layout(binding = 0) coherent buffer Output {\n"
+                       << "    uint result;\n"
+                       << "} sb_out;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    atomicAdd(sb_out.result, 1u);\n"
+                       << "    gl_FragDepth = 0.75f;\n"
+                       << "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                       << "    discard;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+}
+
+class EarlyFragmentSampleMaskTestInstance : public EarlyFragmentTestInstance
+{
+public:
+                                                       EarlyFragmentSampleMaskTestInstance     (Context& context, const deUint32 flags, const deUint32 sampleCount);
+
+       tcu::TestStatus                 iterate                                                         (void);
+
+private:
+       tcu::TextureLevel       generateReferenceColorImage                             (const tcu::TextureFormat format, const tcu::IVec2& renderSize);
+       Move<VkRenderPass>  makeRenderPass                                                      (const DeviceInterface&                         vk,
+                                                                                                                                const VkDevice                                         device,
+                                                                                                                                const VkFormat                                         colorFormat,
+                                                                                                                                const VkFormat                                         depthStencilFormat);
+       Move<VkPipeline>        makeGraphicsPipeline                                    (const DeviceInterface& vk,
+                                                                                                                                const VkDevice                 device,
+                                                                                                                                const VkPipelineLayout pipelineLayout,
+                                                                                                                                const VkRenderPass             renderPass,
+                                                                                                                                const VkShaderModule           vertexModule,
+                                                                                                                                const VkShaderModule           fragmentModule,
+                                                                                                                                const tcu::IVec2&              renderSize,
+                                                                                                                                const bool                             enableDepthTest,
+                                                                                                                                const bool                             enableStencilTest,
+                                                                                                                                const VkStencilOp              stencilFailOp,
+                                                                                                                                const VkStencilOp              stencilPassOp);
+       enum TestMode
+       {
+               MODE_INVALID,
+               MODE_DEPTH,
+               MODE_STENCIL,
+       };
+
+       const TestMode                  m_testMode;
+       const bool                              m_useTestAttachment;
+       const bool                              m_useEarlyTests;
+       const deUint32                  m_sampleCount;
+};
+
+EarlyFragmentSampleMaskTestInstance::EarlyFragmentSampleMaskTestInstance (Context& context, const deUint32 flags, const deUint32 sampleCount)
+       : EarlyFragmentTestInstance                     (context, flags)
+       , m_testMode                    (flags & FLAG_TEST_DEPTH   ? MODE_DEPTH :
+                                                        flags & FLAG_TEST_STENCIL ? MODE_STENCIL : MODE_INVALID)
+       , m_useTestAttachment   ((flags & FLAG_DONT_USE_TEST_ATTACHMENT) == 0)
+       , m_useEarlyTests               ((flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0)
+       , m_sampleCount                 (sampleCount)
+{
+       DE_ASSERT(m_testMode != MODE_INVALID);
+}
+
+tcu::TextureLevel EarlyFragmentSampleMaskTestInstance::generateReferenceColorImage(const tcu::TextureFormat format, const tcu::IVec2 &renderSize)
+{
+       tcu::TextureLevel       image(format, renderSize.x(), renderSize.y());
+       const tcu::Vec4         clearColor      = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+
+       tcu::clear(image.getAccess(), clearColor);
+
+       return image;
+}
+
+Move<VkPipeline> EarlyFragmentSampleMaskTestInstance::makeGraphicsPipeline (const DeviceInterface&     vk,
+                                                                                                                                                       const VkDevice                  device,
+                                                                                                                                                       const VkPipelineLayout  pipelineLayout,
+                                                                                                                                                       const VkRenderPass              renderPass,
+                                                                                                                                                       const VkShaderModule            vertexModule,
+                                                                                                                                                       const VkShaderModule            fragmentModule,
+                                                                                                                                                       const tcu::IVec2&               renderSize,
+                                                                                                                                                       const bool                              enableDepthTest,
+                                                                                                                                                       const bool                              enableStencilTest,
+                                                                                                                                                       const VkStencilOp               stencilFailOp,
+                                                                                                                                                       const VkStencilOp               stencilPassOp)
+{
+       const std::vector<VkViewport>                   viewports                                       (1, makeViewport(renderSize));
+       const std::vector<VkRect2D>                             scissors                                        (1, makeRect2D(renderSize));
+
+       const VkStencilOpState                                  stencilOpState                          = makeStencilOpState(
+               stencilFailOp,                  // stencil fail
+               stencilPassOp,                  // depth & stencil pass
+               VK_STENCIL_OP_KEEP,             // depth only fail
+               VK_COMPARE_OP_EQUAL,    // compare op
+               0x3,                                    // compare mask
+               0xf,                                    // write mask
+               1u);                                    // reference
+
+       const VkPipelineDepthStencilStateCreateInfo     depthStencilStateCreateInfo     =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                          sType
+               DE_NULL,                                                                                                        // const void*                              pNext
+               0u,                                                                                                                     // VkPipelineDepthStencilStateCreateFlags   flags
+               enableDepthTest ? VK_TRUE : VK_FALSE,                                           // VkBool32                                 depthTestEnable
+               enableDepthTest ? VK_TRUE : VK_FALSE,                                           // VkBool32                                 depthWriteEnable
+               VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                              depthCompareOp
+               VK_FALSE,                                                                                                       // VkBool32                                 depthBoundsTestEnable
+               enableStencilTest ? VK_TRUE : VK_FALSE,                                         // VkBool32                                 stencilTestEnable
+               stencilOpState,                                                                                         // VkStencilOpState                         front
+               stencilOpState,                                                                                         // VkStencilOpState                         back
+               0.0f,                                                                                                           // float                                    minDepthBounds
+               1.0f                                                                                                            // float                                    maxDepthBounds
+       };
+
+       // Only allow coverage on sample 0.
+       const VkSampleMask sampleMask = 0x1;
+
+       const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType
+               DE_NULL,                                                                                                        // const void*                                                          pNext
+               0u,                                                                                                                     // VkPipelineMultisampleStateCreateFlags        flags
+               (VkSampleCountFlagBits)m_sampleCount,                                           // VkSampleCountFlagBits                                        rasterizationSamples
+               DE_TRUE,                                                                                                        // VkBool32                                                                     sampleShadingEnable
+               0.0f,                                                                                                           // float                                                                        minSampleShading
+               &sampleMask,                                                                                            // const VkSampleMask*                                          pSampleMask
+               DE_FALSE,                                                                                                       // VkBool32                                                                     alphaToCoverageEnable
+               DE_FALSE,                                                                                                       // VkBool32                                                                     alphaToOneEnable
+       };
+
+       return vk::makeGraphicsPipeline(vk,                                                                             // const DeviceInterface&                        vk
+                                                                       device,                                                                 // const VkDevice                                device
+                                                                       pipelineLayout,                                                 // const VkPipelineLayout                        pipelineLayout
+                                                                       vertexModule,                                                   // const VkShaderModule                          vertexShaderModule
+                                                                       DE_NULL,                                                                // const VkShaderModule                          tessellationControlModule
+                                                                       DE_NULL,                                                                // const VkShaderModule                          tessellationEvalModule
+                                                                       DE_NULL,                                                                // const VkShaderModule                          geometryShaderModule
+                                                                       fragmentModule,                                                 // const VkShaderModule                          fragmentShaderModule
+                                                                       renderPass,                                                             // const VkRenderPass                            renderPass
+                                                                       viewports,                                                              // const std::vector<VkViewport>&                viewports
+                                                                       scissors,                                                               // const std::vector<VkRect2D>&                  scissors
+                                                                       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,    // const VkPrimitiveTopology                     topology
+                                                                       0u,                                                                             // const deUint32                                subpass
+                                                                       0u,                                                                             // const deUint32                                patchControlPoints
+                                                                       DE_NULL,                                                                // const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
+                                                                       DE_NULL,                                                                // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
+                                                                       &multisampleStateCreateInfo,                    // const VkPipelineMultisampleStateCreateInfo*   multisampleStateCreateInfo
+                                                                       &depthStencilStateCreateInfo);                  // const VkPipelineDepthStencilStateCreateInfo*  depthStencilStateCreateInfo
+}
+
+Move<VkRenderPass> EarlyFragmentSampleMaskTestInstance::makeRenderPass (const DeviceInterface&                         vk,
+                                                                                                                                               const VkDevice                                          device,
+                                                                                                                                               const VkFormat                                          colorFormat,
+                                                                                                                                               const VkFormat                                          depthStencilFormat)
+{
+       const bool                                                              hasColor                                                        = colorFormat != VK_FORMAT_UNDEFINED;
+       const bool                                                              hasDepthStencil                                         = depthStencilFormat != VK_FORMAT_UNDEFINED;
+
+
+       const VkAttachmentDescription2                  colorAttachmentDescription                      =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,     // VkStructureType                                      sType;
+               DE_NULL,                                                                        // const void*                                          pNext;
+               (VkAttachmentDescriptionFlags)0,                        // VkAttachmentDescriptionFlags    flags
+               colorFormat,                                                            // VkFormat                        format
+               (VkSampleCountFlagBits)m_sampleCount,           // VkSampleCountFlagBits           samples
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                            // VkAttachmentLoadOp              loadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                           // VkAttachmentStoreOp             storeOp
+               VK_ATTACHMENT_LOAD_OP_DONT_CARE,                        // VkAttachmentLoadOp              stencilLoadOp
+               VK_ATTACHMENT_STORE_OP_DONT_CARE,                       // VkAttachmentStoreOp             stencilStoreOp
+               VK_IMAGE_LAYOUT_UNDEFINED,                                      // VkImageLayout                   initialLayout
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL        // VkImageLayout                   finalLayout
+       };
+
+       const VkAttachmentDescription2                  depthStencilAttachmentDescription       =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,                     // VkStructureType                                      sType;
+               DE_NULL,                                                                                        // const void*                                          pNext;
+               (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags    flags
+               depthStencilFormat,                                                                     // VkFormat                        format
+               (VkSampleCountFlagBits)m_sampleCount,                           // VkSampleCountFlagBits           samples
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp              loadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp             storeOp
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp              stencilLoadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp             stencilStoreOp
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,       // VkImageLayout                   initialLayout
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL        // VkImageLayout                   finalLayout
+       };
+
+       const VkAttachmentDescription2                  resolveAttachmentDescription                    =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,     // VkStructureType                                      sType;
+               DE_NULL,                                                                        // const void*                                          pNext;
+               (VkAttachmentDescriptionFlags)0,                        // VkAttachmentDescriptionFlags    flags
+               colorFormat,                                                            // VkFormat                        format
+               VK_SAMPLE_COUNT_1_BIT,                                          // VkSampleCountFlagBits           samples
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                            // VkAttachmentLoadOp              loadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                           // VkAttachmentStoreOp             storeOp
+               VK_ATTACHMENT_LOAD_OP_DONT_CARE,                        // VkAttachmentLoadOp              stencilLoadOp
+               VK_ATTACHMENT_STORE_OP_DONT_CARE,                       // VkAttachmentStoreOp             stencilStoreOp
+               VK_IMAGE_LAYOUT_UNDEFINED,                                      // VkImageLayout                   initialLayout
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL        // VkImageLayout                   finalLayout
+       };
+
+               const VkAttachmentDescription2          resolveDepthStencilAttachmentDescription        =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,                     // VkStructureType                                      sType;
+               DE_NULL,                                                                                        // const void*                                          pNext;
+               (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags    flags
+               depthStencilFormat,                                                                     // VkFormat                        format
+               VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits           samples
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp              loadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp             storeOp
+               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp              stencilLoadOp
+               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp             stencilStoreOp
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,       // VkImageLayout                   initialLayout
+               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL        // VkImageLayout                   finalLayout
+       };
+
+       std::vector<VkAttachmentDescription2>   attachmentDescriptions;
+
+       if (hasColor)
+               attachmentDescriptions.push_back(colorAttachmentDescription);
+       if (hasDepthStencil)
+               attachmentDescriptions.push_back(depthStencilAttachmentDescription);
+       if (hasColor)
+               attachmentDescriptions.push_back(resolveAttachmentDescription);
+       if (hasDepthStencil)
+               attachmentDescriptions.push_back(resolveDepthStencilAttachmentDescription);
+
+       const VkAttachmentReference2                            colorAttachmentRef                                      =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,                       // VkStructureType              sType;
+               DE_NULL,                                                                                        // const void*                  pNext;
+               0u,                                                                                                     // deUint32         attachment
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout    layout
+               VK_IMAGE_ASPECT_COLOR_BIT                                                       // VkImageAspectFlags   aspectMask;
+       };
+
+       const VkAttachmentReference2                            depthStencilAttachmentRef                       =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,                                                                                               // VkStructureType              sType;
+               DE_NULL,                                                                                                                                                                // const void*                  pNext;
+           hasDepthStencil ? 1u : 0u,                                                                                                                          // deUint32         attachment
+               VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,                                                                                                // VkImageLayout    layout
+           m_testMode == MODE_DEPTH ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT          // VkImageAspectFlags   aspectMask;
+       };
+
+       const VkAttachmentReference2                            resolveAttachmentRef                                    =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,                       // VkStructureType              sType;
+               DE_NULL,                                                                                        // const void*                  pNext;
+               hasColor ? 2u : 0u,                                                                     // deUint32         attachment
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout    layout
+               VK_IMAGE_ASPECT_COLOR_BIT                                                       // VkImageAspectFlags   aspectMask;
+       };
+
+       const VkAttachmentReference2                            depthStencilResolveAttachmentRef                        =
+       {
+               VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,                                                                                               // VkStructureType              sType;
+               DE_NULL,                                                                                                                                                                // const void*                  pNext;
+           hasDepthStencil ? 3u : 0u,                                                                                                                          // deUint32         attachment
+               VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,                                                                                                // VkImageLayout    layout
+           m_testMode == MODE_DEPTH ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT          // VkImageAspectFlags   aspectMask;
+       };
+
+       // Using VK_RESOLVE_MODE_SAMPLE_ZERO_BIT as resolve mode, so no need to check its support as it is mandatory in the extension.
+       const VkSubpassDescriptionDepthStencilResolve depthStencilResolveDescription =
+       {
+               VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE,    // VkStructureType                                      sType;
+               DE_NULL,                                                                                                                // const void*                                          pNext;
+               VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,                                                                // VkResolveModeFlagBits                        depthResolveMode;
+               VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,                                                                // VkResolveModeFlagBits                        stencilResolveMode;
+               &depthStencilResolveAttachmentRef                                                               // const VkAttachmentReference2*        pDepthStencilResolveAttachment;
+       };
+
+       const VkSubpassDescription2                             subpassDescription                                      =
+       {
+               VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,                                                // VkStructureType                                      sType;
+               hasDepthStencil ? &depthStencilResolveDescription : DE_NULL,    // const void*                                          pNext;
+               (VkSubpassDescriptionFlags)0,                                                                   // VkSubpassDescriptionFlags            flags
+               VK_PIPELINE_BIND_POINT_GRAPHICS,                                                                // VkPipelineBindPoint                          pipelineBindPoint
+               0u,                                                                                                                             // deUint32                                                     viewMask;
+               0u,                                                                                                                             // deUint32                                                     inputAttachmentCount
+               DE_NULL,                                                                                                                // const VkAttachmentReference2*        pInputAttachments
+               hasColor ? 1u : 0u,                                                                                             // deUint32                                                     colorAttachmentCount
+               hasColor ? &colorAttachmentRef : DE_NULL,                                               // const VkAttachmentReference2*        pColorAttachments
+               hasColor ? &resolveAttachmentRef : DE_NULL,                                             // const VkAttachmentReference2*        pResolveAttachments
+               hasDepthStencil ? &depthStencilAttachmentRef : DE_NULL,                 // const VkAttachmentReference2*        pDepthStencilAttachment
+               0u,                                                                                                                             // deUint32                                                     preserveAttachmentCount
+               DE_NULL                                                                                                                 // const deUint32*                                      pPreserveAttachments
+       };
+
+       const VkRenderPassCreateInfo2                   renderPassInfo                                          =
+       {
+               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,                                                            // VkStructureType                   sType
+               DE_NULL,                                                                                                                                        // const void*                       pNext
+               (VkRenderPassCreateFlags)0,                                                                                                     // VkRenderPassCreateFlags           flags
+               (deUint32)attachmentDescriptions.size(),                                                                        // deUint32                          attachmentCount
+               attachmentDescriptions.size() > 0 ? &attachmentDescriptions[0] : DE_NULL,       // const VkAttachmentDescription2*    pAttachments
+               1u,                                                                                                                                                     // deUint32                          subpassCount
+               &subpassDescription,                                                                                                            // const VkSubpassDescription2*       pSubpasses
+               0u,                                                                                                                                                     // deUint32                          dependencyCount
+               DE_NULL,                                                                                                                                        // const VkSubpassDependency*        pDependencies
+               0u,                                                                                                                                                     // deUint32                                             correlatedViewMaskCount;
+               DE_NULL,                                                                                                                                        // const deUint32*                                      pCorrelatedViewMasks;
+       };
+
+       return createRenderPass2(vk, device, &renderPassInfo, DE_NULL);
+}
+
+tcu::TestStatus EarlyFragmentSampleMaskTestInstance::iterate (void)
+{
+       const DeviceInterface&          vk                                      = m_context.getDeviceInterface();
+       const InstanceInterface&        vki                                     = m_context.getInstanceInterface();
+       const VkDevice                          device                          = m_context.getDevice();
+       const VkPhysicalDevice          physDevice                      = m_context.getPhysicalDevice();
+       const VkQueue                           queue                           = m_context.getUniversalQueue();
+       const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       Allocator&                                      allocator                       = m_context.getDefaultAllocator();
+       const VkFormat                          colorFormat                     = VK_FORMAT_R8G8B8A8_UNORM;
+
+       DE_ASSERT(m_useTestAttachment);
+
+       // Test attachment (depth or stencil)
+       static const VkFormat stencilFormats[] =
+       {
+               // One of the following formats must be supported, as per spec requirement.
+               VK_FORMAT_S8_UINT,
+               VK_FORMAT_D16_UNORM_S8_UINT,
+               VK_FORMAT_D24_UNORM_S8_UINT,
+               VK_FORMAT_D32_SFLOAT_S8_UINT,
+       };
+
+       const VkFormat depthStencilFormat = (m_testMode == MODE_STENCIL ? pickSupportedDepthStencilFormat(vki, physDevice, DE_LENGTH_OF_ARRAY(stencilFormats), stencilFormats)
+                                                                                : VK_FORMAT_D16_UNORM);                // spec requires this format to be supported
+
+       if (depthStencilFormat == VK_FORMAT_UNDEFINED)
+               return tcu::TestStatus::fail("Required depth/stencil format not supported");
+
+       m_context.getTestContext().getLog() << tcu::TestLog::Message << "Using depth/stencil format " << getFormatName(depthStencilFormat) << tcu::TestLog::EndMessage;
+
+       // Check support for MSAA image formats used in the test.
+       VkImageFormatProperties formatProperties;
+       vki.getPhysicalDeviceImageFormatProperties(physDevice, colorFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u, &formatProperties);
+       if ((formatProperties.sampleCounts & m_sampleCount) == 0)
+               TCU_THROW(NotSupportedError, "Format does not support this number of samples for color format");
+
+       vki.getPhysicalDeviceImageFormatProperties(physDevice, depthStencilFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u, &formatProperties);
+       if ((formatProperties.sampleCounts & m_sampleCount) == 0)
+               TCU_THROW(NotSupportedError, "Format does not support this number of samples for depth-stencil format");
+
+       // Color attachment
+       const tcu::IVec2                                renderSize                              = tcu::IVec2(32, 32);
+       const VkImageSubresourceRange   colorSubresourceRange   = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+
+       const VkImageCreateInfo imageParams =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+               DE_NULL,                                                                                                                                        // const void*                          pNext;
+               (VkImageCreateFlags)0,                                                                                                          // VkImageCreateFlags           flags;
+               VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+               colorFormat,                                                                                                                            // VkFormat                                     format;
+               makeExtent3D(renderSize.x(), renderSize.y(), 1),                                                        // VkExtent3D                           extent;
+               1u,                                                                                                                                                     // deUint32                                     mipLevels;
+               1u,                                                                                                                                                     // deUint32                                     arrayLayers;
+               (VkSampleCountFlagBits)m_sampleCount,                                                                           // VkSampleCountFlagBits        samples;
+               VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+               0u,                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+               DE_NULL,                                                                                                                                        // const deUint32*                      pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        initialLayout;
+       };
+       const Unique<VkImage>                   colorImage                              (makeImage(vk, device, imageParams));
+       const UniquePtr<Allocation>             colorImageAlloc                 (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               colorImageView                  (makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
+
+       const Unique<VkImage>                   resolveColorImage               (makeImage(vk, device, makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
+       const UniquePtr<Allocation>             resolveColorImageAlloc  (bindImage(vk, device, allocator, *resolveColorImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               resolveColorImageView   (makeImageView(vk, device, *resolveColorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
+
+       // Depth-Stencil attachment
+       const VkImageSubresourceRange   depthStencilSubresourceRange    = makeImageSubresourceRange(getImageAspectFlags(depthStencilFormat), 0u, 1u, 0u, 1u);
+
+       const VkImageCreateInfo depthStencilImageParams =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                                            // VkStructureType                      sType;
+               DE_NULL,                                                                                                                                                        // const void*                          pNext;
+               (VkImageCreateFlags)0,                                                                                                                          // VkImageCreateFlags           flags;
+               VK_IMAGE_TYPE_2D,                                                                                                                                       // VkImageType                          imageType;
+               depthStencilFormat,                                                                                                                                                     // VkFormat                                     format;
+               makeExtent3D(renderSize.x(), renderSize.y(), 1),                                                                        // VkExtent3D                           extent;
+               1u,                                                                                                                                                                     // deUint32                                     mipLevels;
+               1u,                                                                                                                                                                     // deUint32                                     arrayLayers;
+               (VkSampleCountFlagBits)m_sampleCount,                                                                                           // VkSampleCountFlagBits        samples;
+               VK_IMAGE_TILING_OPTIMAL,                                                                                                                        // VkImageTiling                        tiling;
+               VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                                                                                                      // VkSharingMode                        sharingMode;
+               0u,                                                                                                                                                                     // deUint32                                     queueFamilyIndexCount;
+               DE_NULL,                                                                                                                                                        // const deUint32*                      pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                                      // VkImageLayout                        initialLayout;
+       };
+       const Unique<VkImage>                   depthStencilImage                               (makeImage(vk, device, depthStencilImageParams));
+       const UniquePtr<Allocation>             depthStencilImageAlloc                  (bindImage(vk, device, allocator, *depthStencilImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               depthStencilImageView                   (makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, depthStencilFormat, depthStencilSubresourceRange));
+
+       const Unique<VkImage>                   resolveDepthStencilImage                                (makeImage(vk, device, makeImageCreateInfo(renderSize, depthStencilFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
+       const UniquePtr<Allocation>             resolveDepthStencilImageAlloc                   (bindImage(vk, device, allocator, *resolveDepthStencilImage, MemoryRequirement::Any));
+       const Unique<VkImageView>               resolveDepthStencilImageView                    (makeImageView(vk, device, *resolveDepthStencilImage, VK_IMAGE_VIEW_TYPE_2D, depthStencilFormat, depthStencilSubresourceRange));
+
+       const VkImageView                               attachmentImages[]              = { *colorImageView, *depthStencilImageView, *resolveColorImageView, *resolveDepthStencilImageView };
+       const deUint32                                  numUsedAttachmentImages = DE_LENGTH_OF_ARRAY(attachmentImages);
+
+       // Vertex buffer
+
+       const deUint32                                  numVertices                             = 6u;
+       const VkDeviceSize                              vertexBufferSizeBytes   = sizeof(tcu::Vec4) * numVertices;
+       const Unique<VkBuffer>                  vertexBuffer                    (makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
+       const UniquePtr<Allocation>             vertexBufferAlloc               (bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
+
+       {
+               tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
+
+               pVertices[0] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
+               pVertices[1] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
+               pVertices[2] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
+
+               pVertices[3] = tcu::Vec4(-1.0f,  1.0f,  0.5f,  1.0f);
+               pVertices[4] = tcu::Vec4( 1.0f,  1.0f,  1.0f,  1.0f);
+               pVertices[5] = tcu::Vec4( 1.0f, -1.0f,  0.5f,  1.0f);
+
+               flushAlloc(vk, device, *vertexBufferAlloc);
+               // No barrier needed, flushed memory is automatically visible
+       }
+
+       // Result buffer
+
+       const VkDeviceSize                              resultBufferSizeBytes   = sizeof(deUint32);
+       const Unique<VkBuffer>                  resultBuffer                    (makeBuffer(vk, device, resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
+       const UniquePtr<Allocation>             resultBufferAlloc               (bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
+
+       {
+               deUint32* const pData = static_cast<deUint32*>(resultBufferAlloc->getHostPtr());
+
+               *pData = 0;
+               flushAlloc(vk, device, *resultBufferAlloc);
+       }
+
+       // Render result buffer (to retrieve color attachment contents)
+
+       const VkDeviceSize                              colorBufferSizeBytes    = tcu::getPixelSize(mapVkFormat(colorFormat)) * renderSize.x() * renderSize.y();
+       const Unique<VkBuffer>                  colorBuffer                             (makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+       const UniquePtr<Allocation>             colorBufferAlloc                (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
+
+       // Depth stencil result buffer (to retrieve depth-stencil attachment contents)
+
+       const VkDeviceSize                              dsBufferSizeBytes       = tcu::getPixelSize(mapVkFormat(depthStencilFormat)) * renderSize.x() * renderSize.y();
+       const Unique<VkBuffer>                  dsBuffer                        (makeBuffer(vk, device, dsBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
+       const UniquePtr<Allocation>             dsBufferAlloc           (bindBuffer(vk, device, allocator, *dsBuffer, MemoryRequirement::HostVisible));
+
+       // Descriptors
+
+       const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
+               .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
+               .build(vk, device));
+
+       const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
+               .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
+               .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
+
+       const Unique<VkDescriptorSet> descriptorSet                              (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
+       const VkDescriptorBufferInfo  resultBufferDescriptorInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
+
+       DescriptorSetUpdateBuilder()
+               .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferDescriptorInfo)
+               .update(vk, device);
+
+       // Pipeline
+
+       const Unique<VkShaderModule>    vertexModule  (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
+       const Unique<VkShaderModule>    fragmentModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
+
+       const Unique<VkRenderPass>              renderPass        (makeRenderPass(vk, device, colorFormat, depthStencilFormat));
+       const Unique<VkFramebuffer>             framebuffer       (makeFramebuffer(vk, device, *renderPass, numUsedAttachmentImages, attachmentImages, renderSize.x(), renderSize.y()));
+       const Unique<VkPipelineLayout>  pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
+       const Unique<VkPipeline>                pipeline          (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, renderSize,
+                                                                                                                                               (m_testMode == MODE_DEPTH), (m_testMode == MODE_STENCIL),
+                                                                                                                                               VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP));
+       const Unique<VkCommandPool>             cmdPool           (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer         (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+
+       // Draw commands
+
+       {
+               const VkRect2D renderArea = {
+                       makeOffset2D(0, 0),
+                       makeExtent2D(renderSize.x(), renderSize.y()),
+               };
+               const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
+               const VkDeviceSize vertexBufferOffset = 0ull;
+
+               beginCommandBuffer(vk, *cmdBuffer);
+
+               {
+                       const VkImageMemoryBarrier barriers[] = {
+                               makeImageMemoryBarrier(
+                                       0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                                       *colorImage, colorSubresourceRange),
+                               makeImageMemoryBarrier(
+                                       0u, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+                                       *depthStencilImage, depthStencilSubresourceRange),
+                               makeImageMemoryBarrier(
+                                       0u,  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                                       *resolveColorImage, colorSubresourceRange),
+                               makeImageMemoryBarrier(
+                                       0u, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                                       VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+                                       *resolveDepthStencilImage, depthStencilSubresourceRange),
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
+               }
+
+               // Will clear the attachments with specified depth and stencil values.
+               {
+                       const VkClearValue                      clearValues[]           =
+                               {
+                                       makeClearValueColor(clearColor),                                                // attachment 0
+                                       makeClearValueDepthStencil(0.5f, 3u),                                   // attachment 1
+                                       makeClearValueColor(clearColor),                                                // attachment 2
+                                       makeClearValueDepthStencil(0.5f, 3u),                                   // attachment 3
+                               };
+
+                       const VkRenderPassBeginInfo     renderPassBeginInfo     =
+                               {
+                                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // VkStructureType         sType;
+                                       DE_NULL,                                                                        // const void*             pNext;
+                                       *renderPass,                                                            // VkRenderPass            renderPass;
+                                       *framebuffer,                                                           // VkFramebuffer           framebuffer;
+                                       renderArea,                                                                     // VkRect2D                renderArea;
+                                       DE_LENGTH_OF_ARRAY(clearValues),                        // deUint32                clearValueCount;
+                                       clearValues,                                                            // const VkClearValue*     pClearValues;
+                               };
+
+                       vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+               }
+
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+               vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
+               vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
+
+               // Mask half of the attachment image with value that will pass the stencil test.
+               if (m_testMode == MODE_STENCIL)
+                       commandClearStencilAttachment(vk, *cmdBuffer, makeOffset2D(0, 0), makeExtent2D(renderSize.x()/2, renderSize.y()), 1u);
+
+               vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
+               endRenderPass(vk, *cmdBuffer);
+
+               copyImageToBuffer(vk, *cmdBuffer, *resolveColorImage, *colorBuffer, renderSize, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
+               VkImageAspectFlags dsAspect = m_testMode == MODE_DEPTH ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
+               copyImageToBuffer(vk, *cmdBuffer, *resolveDepthStencilImage, *dsBuffer, renderSize, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1u, dsAspect, dsAspect);
+
+               endCommandBuffer(vk, *cmdBuffer);
+               submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+       }
+
+       // Verify color output
+       {
+               invalidateAlloc(vk, device, *colorBufferAlloc);
+
+               const tcu::ConstPixelBufferAccess       imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc->getHostPtr());
+               const tcu::TextureLevel                         referenceImage  = generateReferenceColorImage(mapVkFormat(colorFormat), renderSize);
+               if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", referenceImage.getAccess(), imagePixelAccess, tcu::Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
+                       printf("Rendered color image is not correct");
+       }
+
+       // Verify depth-stencil output
+       {
+               invalidateAlloc(vk, device, *dsBufferAlloc);
+               tcu::TextureFormat format = mapVkFormat(depthStencilFormat);
+               const tcu::ConstPixelBufferAccess       dsPixelAccess (format, renderSize.x(), renderSize.y(), 1, dsBufferAlloc->getHostPtr());
+
+               for(int z = 0; z < dsPixelAccess.getDepth(); z++)
+               for(int y = 0; y < dsPixelAccess.getHeight(); y++)
+               for(int x = 0; x < dsPixelAccess.getWidth(); x++)
+               {
+                       float   depthValue              = (m_testMode == MODE_DEPTH) ? dsPixelAccess.getPixDepth(x, y, z) : 0.0f;
+                       int             stencilValue    = (m_testMode == MODE_STENCIL) ? dsPixelAccess.getPixStencil(x, y, z) : 0;
+
+                       // Depth test should write to the depth buffer even when there is a discard in the fragment shader,
+                       // when early fragment tests are enabled.
+                       if (m_testMode == MODE_DEPTH)
+                       {
+                               if (m_useEarlyTests && ((x + y) < 31) && depthValue >= 0.5f)
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered depth value [ "<< x << ", " << y << ", " << z << "] is not correct: " << depthValue << " >= 0.5f";
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                               // When early fragment tests are disabled, the depth test happens after the fragment shader, but as we are discarding
+                               // all fragments, the stored value in the depth buffer should be the clear one (0.5f).
+                               if (!m_useEarlyTests && deAbs(depthValue - 0.5f) > 0.01f)
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered depth value [ "<< x << ", " << y << ", " << z << "] is not correct: " << depthValue << " != 0.5f";
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                       }
+
+                       if (m_testMode == MODE_STENCIL)
+                       {
+                               if (m_useEarlyTests && ((x < 16 && stencilValue != 2u) || (x >= 16 && stencilValue != 4u)))
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered stencil value [ "<< x << ", " << y << ", " << z << "] is not correct: " << stencilValue << " != ";
+                                       error << (x < 16 ? 2u : 4u);
+                                       TCU_FAIL(error.str().c_str());
+                               }
+
+                               if (!m_useEarlyTests && ((x < 16 && stencilValue != 1u) || (x >= 16 && stencilValue != 3u)))
+                               {
+                                       std::ostringstream error;
+                                       error << "Rendered stencil value [ "<< x << ", " << y << ", " << z << "] is not correct: " << stencilValue << " != ";
+                                       error << (x < 16 ? 1u : 3u);
+                                       TCU_FAIL(error.str().c_str());
+                               }
+                       }
+               }
+       }
+
+       // Verify we process all the fragments
+       {
+               invalidateAlloc(vk, device, *resultBufferAlloc);
+
+               const int  actualCounter           = *static_cast<deInt32*>(resultBufferAlloc->getHostPtr());
+               const bool expectPartialResult = m_useEarlyTests;
+               const int  expectedCounter         = expectPartialResult ? renderSize.x() * renderSize.y() / 2 : renderSize.x() * renderSize.y();
+               const int  tolerance               = expectPartialResult ? de::max(renderSize.x(), renderSize.y()) * 3  : 0;
+               const int  expectedMin         = de::max(0, expectedCounter - tolerance);
+               const int  expectedMax             = expectedCounter + tolerance;
+
+               tcu::TestLog& log = m_context.getTestContext().getLog();
+               log << tcu::TestLog::Message << "Expected value"
+                       << (expectPartialResult ? " in range: [" + de::toString(expectedMin) + ", " + de::toString(expectedMax) + "]" : ": " + de::toString(expectedCounter))
+                       << tcu::TestLog::EndMessage;
+               log << tcu::TestLog::Message << "Result value: " << de::toString(actualCounter) << tcu::TestLog::EndMessage;
+
+               if (expectedMin <= actualCounter && actualCounter <= expectedMax)
+                       return tcu::TestStatus::pass("Success");
+               else
+                       return tcu::TestStatus::fail("Value out of range");
+       }
+}
+
+class EarlyFragmentSampleMaskTest : public EarlyFragmentTest
+{
+public:
+                                               EarlyFragmentSampleMaskTest     (tcu::TestContext&              testCtx,
+                                                                                                        const std::string              name,
+                                                                                                        const deUint32                 flags,
+                                                                                                        const deUint32                 sampleCount);
+
+       void                            initPrograms                            (SourceCollections&             programCollection) const override;
+       TestInstance*           createInstance                          (Context&                               context) const override;
+       void                            checkSupport                            (Context&                               context) const override;
+
+private:
+       const deUint32          m_flags;
+       const deUint32          m_sampleCount;
+};
+
+EarlyFragmentSampleMaskTest::EarlyFragmentSampleMaskTest (tcu::TestContext& testCtx, const std::string name, const deUint32 flags, const deUint32 sampleCount)
+       : EarlyFragmentTest     (testCtx, name, flags)
+       , m_flags (flags)
+       , m_sampleCount (sampleCount)
+{
+}
+
+TestInstance* EarlyFragmentSampleMaskTest::createInstance (Context& context) const
+{
+       return new EarlyFragmentSampleMaskTestInstance(context, m_flags, m_sampleCount);
+}
+
+void EarlyFragmentSampleMaskTest::initPrograms(SourceCollections &programCollection) const
+{
+       // Vertex
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
+                       << "\n"
+                       << "layout(location = 0) in highp vec4 position;\n"
+                       << "\n"
+                       << "out gl_PerVertex {\n"
+                       << "   vec4 gl_Position;\n"
+                       << "};\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    gl_Position = position;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment
+       {
+               const bool useEarlyTests = (m_flags & FLAG_DONT_USE_EARLY_FRAGMENT_TESTS) == 0;
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
+                       << "\n"
+                       << (useEarlyTests ? "layout(early_fragment_tests) in;\n" : "")
+                       << "layout(location = 0) out highp vec4 fragColor;\n"
+                       << "\n"
+                       << "layout(binding = 0) coherent buffer Output {\n"
+                       << "    uint result;\n"
+                       << "} sb_out;\n"
+                       << "\n"
+                       << "void main (void)\n"
+                       << "{\n"
+                       << "    atomicAdd(sb_out.result, 1u);\n"
+                       << "    gl_SampleMask[0] = 0x0;\n"
+                       << "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                       << "    discard;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+}
+
+void EarlyFragmentSampleMaskTest::checkSupport(Context& context) const
+{
+       EarlyFragmentTest::checkSupport(context);
+
+       context.requireDeviceFunctionality("VK_KHR_depth_stencil_resolve");
+}
+
 } // anonymous ns
 
 tcu::TestCaseGroup* createEarlyFragmentTests (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "early_fragment", "early fragment test cases"));
 
-       static const struct
        {
-               std::string caseName;
-               deUint32        flags;
-       } cases[] =
+               static const struct
+               {
+                       std::string caseName;
+                       deUint32        flags;
+               } cases[] =
+               {
+                       { "no_early_fragment_tests_depth",                                      FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
+                       { "no_early_fragment_tests_stencil",                            FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
+                       { "early_fragment_tests_depth",                                         FLAG_TEST_DEPTH                                                                                                                                                 },
+                       { "early_fragment_tests_stencil",                                       FLAG_TEST_STENCIL                                                                                                                                               },
+                       { "no_early_fragment_tests_depth_no_attachment",        FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT  },
+                       { "no_early_fragment_tests_stencil_no_attachment",      FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT  },
+                       { "early_fragment_tests_depth_no_attachment",           FLAG_TEST_DEPTH   |                                                                              FLAG_DONT_USE_TEST_ATTACHMENT  },
+                       { "early_fragment_tests_stencil_no_attachment",         FLAG_TEST_STENCIL |                                                                              FLAG_DONT_USE_TEST_ATTACHMENT  },
+               };
+
+               for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
+                       testGroup->addChild(new EarlyFragmentTest(testCtx, cases[i].caseName, cases[i].flags));
+       }
+
+       // Check that discard does not affect depth test writes.
+       {
+               static const struct
+               {
+                       std::string caseName;
+                       deUint32        flags;
+               } cases[] =
+               {
+                       { "discard_no_early_fragment_tests_depth",                                      FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
+                       { "discard_no_early_fragment_tests_stencil",                            FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
+                       { "discard_early_fragment_tests_depth",                                         FLAG_TEST_DEPTH                                                                                                                                                 },
+                       { "discard_early_fragment_tests_stencil",                                       FLAG_TEST_STENCIL                                                                                                                                               },
+               };
+
+               for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
+                       testGroup->addChild(new EarlyFragmentDiscardTest(testCtx, cases[i].caseName, cases[i].flags));
+       }
+
+       // Check that writing to gl_SampleMask does not affect depth test writes.
        {
-               { "no_early_fragment_tests_depth",                                      FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
-               { "no_early_fragment_tests_stencil",                            FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS                                                                  },
-               { "early_fragment_tests_depth",                                         FLAG_TEST_DEPTH                                                                                                                                                 },
-               { "early_fragment_tests_stencil",                                       FLAG_TEST_STENCIL                                                                                                                                               },
-               { "no_early_fragment_tests_depth_no_attachment",        FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT  },
-               { "no_early_fragment_tests_stencil_no_attachment",      FLAG_TEST_STENCIL | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS | FLAG_DONT_USE_TEST_ATTACHMENT  },
-               { "early_fragment_tests_depth_no_attachment",           FLAG_TEST_DEPTH   |                                                                              FLAG_DONT_USE_TEST_ATTACHMENT  },
-               { "early_fragment_tests_stencil_no_attachment",         FLAG_TEST_STENCIL |                                                                              FLAG_DONT_USE_TEST_ATTACHMENT  },
-       };
+               static const struct
+               {
+                       std::string caseName;
+                       deUint32        flags;
+               } cases[] =
+               {
+                       { "samplemask_no_early_fragment_tests_depth",                           FLAG_TEST_DEPTH   | FLAG_DONT_USE_EARLY_FRAGMENT_TESTS,                                                                 },
+                       { "samplemask_early_fragment_tests_depth",                                      FLAG_TEST_DEPTH,                                                                                                                                                },
+               };
+
+               const VkSampleCountFlags sampleCounts[] = { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT };
+               const std::string sampleCountsStr[] = { "samples_2", "samples_4", "samples_8", "samples_16" };
 
-       for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
-               testGroup->addChild(new EarlyFragmentTest(testCtx, cases[i].caseName, cases[i].flags));
+               for (deUint32 sampleCountsNdx = 0; sampleCountsNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountsNdx++)
+               {
+                       for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
+                               testGroup->addChild(new EarlyFragmentSampleMaskTest(testCtx, cases[i].caseName + "_" + sampleCountsStr[sampleCountsNdx], cases[i].flags, sampleCounts[sampleCountsNdx]));
+        }
+       }
 
        return testGroup.release();
 }
index ab0c7b8..1491230 100644 (file)
@@ -33,3 +33,15 @@ dEQP-VK.fragment_operations.early_fragment.no_early_fragment_tests_depth_no_atta
 dEQP-VK.fragment_operations.early_fragment.no_early_fragment_tests_stencil_no_attachment
 dEQP-VK.fragment_operations.early_fragment.early_fragment_tests_depth_no_attachment
 dEQP-VK.fragment_operations.early_fragment.early_fragment_tests_stencil_no_attachment
+dEQP-VK.fragment_operations.early_fragment.discard_no_early_fragment_tests_depth
+dEQP-VK.fragment_operations.early_fragment.discard_no_early_fragment_tests_stencil
+dEQP-VK.fragment_operations.early_fragment.discard_early_fragment_tests_depth
+dEQP-VK.fragment_operations.early_fragment.discard_early_fragment_tests_stencil
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_2
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_2
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_4
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_4
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_8
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_8
+dEQP-VK.fragment_operations.early_fragment.samplemask_no_early_fragment_tests_depth_samples_16
+dEQP-VK.fragment_operations.early_fragment.samplemask_early_fragment_tests_depth_samples_16