Test frag shader side effects are not removed by optimizations
authorRicardo Garcia <rgarcia@igalia.com>
Thu, 7 May 2020 12:15:56 +0000 (14:15 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Fri, 17 Jul 2020 08:37:09 +0000 (04:37 -0400)
This commit adds a net set of tests that check fragment shader side
effects, in the form of an SSBO write, are not removed by optimizations
done when the fragment is discarded by several possible means:

* Calling "discard" for the fragment (translated to OpKill).
* Calling "demote" for the fragment (translated to
  OpDemoteToHelperInvocationEXT).
* Setting SampleMask to zero.
* Setting alphaToCoverageEnable and output 0 in the alpha component.
* Making the depth bounds test fail.
* Making the depth test fail.
* Making the stencil test fail.

New tests:
dEQP-VK.rasterization.frag_side_effects.*

Components: Vulkan
VK-GL-CTS issue: 2336

Change-Id: I6de8a50f137f37538fe614088f289f4ae05d88d0

AndroidGen.mk
android/cts/master/vk-master-2020-03-01.txt
android/cts/master/vk-master.txt
external/vulkancts/framework/vulkan/vkObjUtil.cpp
external/vulkancts/framework/vulkan/vkObjUtil.hpp
external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt
external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp
external/vulkancts/modules/vulkan/vktTestCase.cpp
external/vulkancts/mustpass/master/vk-default.txt

index 94ed9c4..9687e2b 100644 (file)
@@ -262,6 +262,7 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/query_pool/vktQueryPoolPerformanceTests.cpp \
        external/vulkancts/modules/vulkan/query_pool/vktQueryPoolStatisticsTests.cpp \
        external/vulkancts/modules/vulkan/query_pool/vktQueryPoolTests.cpp \
+       external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.cpp \
        external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp \
        external/vulkancts/modules/vulkan/renderpass/vktRenderPassDepthStencilResolveTests.cpp \
        external/vulkancts/modules/vulkan/renderpass/vktRenderPassFragmentDensityMapTests.cpp \
index c6d39cf..5717474 100644 (file)
@@ -194478,6 +194478,24 @@ dEQP-VK.rasterization.provoking_vertex.line_strip
 dEQP-VK.rasterization.provoking_vertex.line_strip_with_adjacency
 dEQP-VK.rasterization.line_continuity.line-strip
 dEQP-VK.rasterization.line_continuity.polygon-mode-lines
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_bounds
+dEQP-VK.rasterization.frag_side_effects.color_at_end.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_end.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_bounds
 dEQP-VK.clipping.clip_volume.depth_clip.point_list
 dEQP-VK.clipping.clip_volume.depth_clip.line_list
 dEQP-VK.clipping.clip_volume.depth_clip.line_list_with_adjacency
index 1f10499..bcf4a17 100644 (file)
@@ -558586,6 +558586,24 @@ dEQP-VK.rasterization.provoking_vertex.line_strip
 dEQP-VK.rasterization.provoking_vertex.line_strip_with_adjacency
 dEQP-VK.rasterization.line_continuity.line-strip
 dEQP-VK.rasterization.line_continuity.polygon-mode-lines
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_bounds
+dEQP-VK.rasterization.frag_side_effects.color_at_end.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_end.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_bounds
 dEQP-VK.clipping.clip_volume.inside.point_list
 dEQP-VK.clipping.clip_volume.inside.line_list
 dEQP-VK.clipping.clip_volume.inside.line_list_with_adjacency
index a65d9b8..933a2f4 100644 (file)
@@ -586,7 +586,7 @@ Move<VkFramebuffer> makeFramebuffer (const DeviceInterface& vk,
                                                                         const VkDevice                 device,
                                                                         const VkRenderPass             renderPass,
                                                                         const deUint32                 attachmentCount,
-                                                                        const VkImageView*             colorAttachments,
+                                                                        const VkImageView*             attachmentsArray,
                                                                         const deUint32                 width,
                                                                         const deUint32                 height,
                                                                         const deUint32                 layers)
@@ -598,7 +598,7 @@ Move<VkFramebuffer> makeFramebuffer (const DeviceInterface& vk,
                (VkFramebufferCreateFlags)0,                            // VkFramebufferCreateFlags     flags;
                renderPass,                                                                     // VkRenderPass                         renderPass;
                attachmentCount,                                                        // uint32_t                                     attachmentCount;
-               colorAttachments,                                                       // const VkImageView*           pAttachments;
+               attachmentsArray,                                                       // const VkImageView*           pAttachments;
                width,                                                                          // uint32_t                                     width;
                height,                                                                         // uint32_t                                     height;
                layers,                                                                         // uint32_t                                     layers;
index f072c31..7678e58 100644 (file)
@@ -127,7 +127,7 @@ Move<VkFramebuffer> makeFramebuffer (const DeviceInterface& vk,
                                                                         const VkDevice                 device,
                                                                         const VkRenderPass             renderPass,
                                                                         const deUint32                 attachmentCount,
-                                                                        const VkImageView*             colorAttachments,
+                                                                        const VkImageView*             attachmentsArray,
                                                                         const deUint32                 width,
                                                                         const deUint32                 height,
                                                                         const deUint32                 layers = 1u);
index 32a9b3d..ca664f6 100644 (file)
@@ -6,6 +6,8 @@ include_directories(
 set(DEQP_VK_RASTERIZATION_SRCS
        vktRasterizationTests.cpp
        vktRasterizationTests.hpp
+       vktRasterizationFragShaderSideEffectsTests.cpp
+       vktRasterizationFragShaderSideEffectsTests.hpp
        )
 
 set(DEQP_VK_RASTERIZATION_LIBS
diff --git a/external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.cpp b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.cpp
new file mode 100644 (file)
index 0000000..9c9d4f1
--- /dev/null
@@ -0,0 +1,739 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 The Khronos Group Inc.
+ * Copyright (c) 2020 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test frag shader side effects are not removed by optimizations.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktRasterizationFragShaderSideEffectsTests.hpp"
+#include "vktTestCase.hpp"
+
+#include "vkQueryUtil.hpp"
+#include "vkObjUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkImageWithMemory.hpp"
+#include "vkBufferWithMemory.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "vkBarrierUtil.hpp"
+#include "vkImageUtil.hpp"
+
+#include "tcuVector.hpp"
+#include "tcuMaybe.hpp"
+#include "tcuTestLog.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include <sstream>
+#include <string>
+#include <memory>
+#include <vector>
+#include <algorithm>
+
+namespace vkt
+{
+namespace rasterization
+{
+
+namespace
+{
+
+enum class CaseType
+{
+       KILL,
+       DEMOTE,
+       SAMPLE_MASK_BEFORE,
+       SAMPLE_MASK_AFTER,
+       ALPHA_COVERAGE_BEFORE,
+       ALPHA_COVERAGE_AFTER,
+       DEPTH_BOUNDS,
+       STENCIL_NEVER,
+       DEPTH_NEVER,
+};
+
+constexpr deUint32 kFramebufferWidth   = 32u;
+constexpr deUint32 kFramebufferHeight  = 32u;
+constexpr deUint32 kTotalPixels                        = kFramebufferWidth * kFramebufferHeight;
+
+constexpr vk::VkFormatFeatureFlags     kNeededColorFeatures    = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
+constexpr vk::VkFormat                         kColorFormat                    = vk::VK_FORMAT_R8G8B8A8_UNORM;
+constexpr vk::VkFormatFeatureFlags     kNeededDSFeatures               = vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+// VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT must be supported for one of these two, according to the spec.
+const vk::VkFormat                                     kDepthStencilFormats[]  = { vk::VK_FORMAT_D32_SFLOAT_S8_UINT, vk::VK_FORMAT_D24_UNORM_S8_UINT };
+
+struct DepthBoundsParameters
+{
+       float minDepthBounds;
+       float maxDepthBounds;
+       float depthValue;
+};
+
+struct TestParams
+{
+       CaseType                                                        caseType;
+       tcu::Vec4                                                       clearColor;
+       tcu::Vec4                                                       drawColor;
+       bool                                                            colorAtEnd;
+       tcu::Maybe<DepthBoundsParameters>       depthBoundsParams;
+
+       TestParams (CaseType type, const tcu::Vec4& clearColor_, const tcu::Vec4& drawColor_, bool colorAtEnd_, const tcu::Maybe<DepthBoundsParameters>& depthBoundsParams_)
+               : caseType                      (type)
+               , clearColor            (clearColor_)
+               , drawColor                     (drawColor_)
+               , colorAtEnd            (colorAtEnd_)
+               , depthBoundsParams     (depthBoundsParams_)
+       {
+               if (caseType == CaseType::DEPTH_BOUNDS)
+                       DE_ASSERT(static_cast<bool>(depthBoundsParams));
+       }
+};
+
+bool expectClearColor (CaseType caseType)
+{
+       return (caseType != CaseType::ALPHA_COVERAGE_BEFORE && caseType != CaseType::ALPHA_COVERAGE_AFTER);
+}
+
+bool needsDepthStencilAttachment (CaseType caseType)
+{
+       return (caseType == CaseType::DEPTH_BOUNDS || caseType == CaseType::DEPTH_NEVER || caseType == CaseType::STENCIL_NEVER);
+}
+
+vk::VkBool32 makeVkBool32 (bool value)
+{
+       return (value ? VK_TRUE : VK_FALSE);
+}
+
+class FragSideEffectsTestCase : public vkt::TestCase
+{
+public:
+                                                       FragSideEffectsTestCase         (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
+       virtual                                 ~FragSideEffectsTestCase        (void) {}
+
+       virtual void                    checkSupport                            (Context& context) const;
+       virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+
+private:
+       TestParams                              m_params;
+};
+
+class FragSideEffectsInstance : public vkt::TestInstance
+{
+public:
+                                                               FragSideEffectsInstance         (Context& context, const TestParams& params);
+       virtual                                         ~FragSideEffectsInstance        (void) {}
+
+       virtual tcu::TestStatus         iterate                                         (void);
+
+private:
+       TestParams                                      m_params;
+};
+
+FragSideEffectsTestCase::FragSideEffectsTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
+       : vkt::TestCase (testCtx, name, description)
+       , m_params              (params)
+{}
+
+void FragSideEffectsTestCase::checkSupport (Context& context) const
+{
+       const auto&     vki                             = context.getInstanceInterface();
+       const auto      physicalDevice  = context.getPhysicalDevice();
+
+       if (m_params.caseType == CaseType::DEPTH_BOUNDS)
+       {
+               const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
+               if (!features.depthBounds)
+                       TCU_THROW(NotSupportedError, "Depth bounds test not supported");
+       }
+       else if (m_params.caseType == CaseType::DEMOTE)
+       {
+               context.requireDeviceFunctionality("VK_EXT_shader_demote_to_helper_invocation");
+       }
+
+       const auto colorFormatProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kColorFormat);
+       if ((colorFormatProperties.optimalTilingFeatures & kNeededColorFeatures) != kNeededColorFeatures)
+               TCU_THROW(NotSupportedError, "Color format lacks required features");
+}
+
+void FragSideEffectsTestCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       std::ostringstream headers;
+       std::ostringstream before;
+       std::ostringstream after;
+
+       std::ostringstream vert;
+       std::ostringstream frag;
+
+       // Depth should be 0 by default unless provided by the depth bounds parameters.
+       const float     meshDepth       = (m_params.depthBoundsParams ? m_params.depthBoundsParams.get().depthValue : 0.0f);
+       const auto&     drawColor       = m_params.drawColor;
+
+       vert
+               << "#version 450\n"
+               << "\n"
+               << "layout (location=0) in vec2 inPos;\n"
+               << "\n"
+               << "void main() {\n"
+               << "    gl_Position = vec4(inPos, " << meshDepth << ", 1.0);\n"
+               << "}\n"
+               ;
+
+       // Prepare output color statement to be used before or after SSBO write.
+       std::ostringstream colorStatement;
+       if (m_params.caseType == CaseType::ALPHA_COVERAGE_BEFORE || m_params.caseType == CaseType::ALPHA_COVERAGE_AFTER)
+       {
+               // In the alpha coverage cases the alpha color value is supposed to be 0.
+               DE_ASSERT(m_params.drawColor.w() == 0.0f);
+
+               // Leave out the alpha component for these cases.
+               colorStatement << "    outColor.rgb = vec3(" << drawColor.x() << ", " << drawColor.y() << ", " << drawColor.z() << ");\n";
+       }
+       else
+       {
+               colorStatement << "    outColor = vec4(" << drawColor.x() << ", " << drawColor.y() << ", " << drawColor.z() << ", " << drawColor.w() << ");\n";
+       }
+
+       switch (m_params.caseType)
+       {
+       case CaseType::KILL:
+               after   << "    discard;\n";
+               break;
+       case CaseType::DEMOTE:
+               headers << "#extension GL_EXT_demote_to_helper_invocation : enable\n";
+               after   << "    demote;\n";
+               break;
+       case CaseType::SAMPLE_MASK_BEFORE:
+               before  << "    gl_SampleMask[0] = 0;\n";
+               break;
+       case CaseType::SAMPLE_MASK_AFTER:
+               after   << "    gl_SampleMask[0] = 0;\n";
+               break;
+       case CaseType::ALPHA_COVERAGE_BEFORE:
+               before  << "    outColor.a = float(" << drawColor.w() << ");\n";
+               break;
+       case CaseType::ALPHA_COVERAGE_AFTER:
+               after   << "    outColor.a = float(" << drawColor.w() << ");\n";
+               break;
+       case CaseType::DEPTH_BOUNDS:
+       case CaseType::STENCIL_NEVER:
+       case CaseType::DEPTH_NEVER:
+               break;
+       default:
+               DE_ASSERT(false); break;
+       }
+
+       frag
+               << "#version 450\n"
+               << "layout(set=0, binding=0, std430) buffer OutputBuffer {\n"
+               << "    int val[" << kTotalPixels << "];\n"
+               << "} outBuffer;\n"
+               << "layout (location=0) out vec4 outColor;\n"
+               << headers.str()
+               << "\n"
+               << "void main() {\n"
+               << "    const ivec2 fragCoord = ivec2(gl_FragCoord);\n"
+               << "    const int bufferIndex = (fragCoord.y * " << kFramebufferWidth << ") + fragCoord.x;\n"
+               << (m_params.colorAtEnd ? "" : colorStatement.str())
+               << before.str()
+               << "    outBuffer.val[bufferIndex] = 1;\n"
+               << after.str()
+               << (m_params.colorAtEnd ? colorStatement.str() : "")
+               << "}\n"
+               ;
+
+       programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
+       programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
+}
+
+TestInstance* FragSideEffectsTestCase::createInstance (Context& context) const
+{
+       return new FragSideEffectsInstance(context, m_params);
+}
+
+FragSideEffectsInstance::FragSideEffectsInstance (Context& context, const TestParams& params)
+       : vkt::TestInstance     (context)
+       , m_params                      (params)
+{}
+
+tcu::TestStatus FragSideEffectsInstance::iterate (void)
+{
+       const auto&     vki                             = m_context.getInstanceInterface();
+       const auto      physicalDevice  = m_context.getPhysicalDevice();
+       const auto&     vkd                             = m_context.getDeviceInterface();
+       const auto      device                  = m_context.getDevice();
+       auto&           alloc                   = m_context.getDefaultAllocator();
+       const auto      queue                   = m_context.getUniversalQueue();
+       const auto      queueIndex              = m_context.getUniversalQueueFamilyIndex();
+
+       // Color and depth/stencil images.
+
+       const vk::VkImageCreateInfo colorCreateInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                                        //      VkStructureType                 sType;
+               nullptr,                                                                                                                                                        //      const void*                             pNext;
+               0u,                                                                                                                                                                     //      VkImageCreateFlags              flags;
+               vk::VK_IMAGE_TYPE_2D,                                                                                                                           //      VkImageType                             imageType;
+               kColorFormat,                                                                                                                                           //      VkFormat                                format;
+               vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u),                                            //      VkExtent3D                              extent;
+               1u,                                                                                                                                                                     //      deUint32                                mipLevels;
+               1u,                                                                                                                                                                     //      deUint32                                arrayLayers;
+               vk::VK_SAMPLE_COUNT_1_BIT,                                                                                                                      //      VkSampleCountFlagBits   samples;
+               vk::VK_IMAGE_TILING_OPTIMAL,                                                                                                            //      VkImageTiling                   tiling;
+               (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT),        //      VkImageUsageFlags               usage;
+               vk::VK_SHARING_MODE_EXCLUSIVE,                                                                                                          //      VkSharingMode                   sharingMode;
+               0u,                                                                                                                                                                     //      deUint32                                queueFamilyIndexCount;
+               nullptr,                                                                                                                                                        //      const deUint32*                 pQueueFamilyIndices;
+               vk::VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                          //      VkImageLayout                   initialLayout;
+       };
+       vk::ImageWithMemory colorImage(vkd, device, alloc, colorCreateInfo, vk::MemoryRequirement::Any);
+
+       std::unique_ptr<vk::ImageWithMemory>    depthStencilImage;
+       vk::VkFormat                                                    depthStencilFormat = vk::VK_FORMAT_UNDEFINED;
+
+       if (needsDepthStencilAttachment(m_params.caseType))
+       {
+               // Find available image format first.
+               for (int i = 0; i < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++i)
+               {
+                       const auto dsFormatProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[i]);
+                       if ((dsFormatProperties.optimalTilingFeatures & kNeededDSFeatures) == kNeededDSFeatures)
+                       {
+                               depthStencilFormat = kDepthStencilFormats[i];
+                               break;
+                       }
+               }
+
+               if (depthStencilFormat == vk::VK_FORMAT_UNDEFINED)
+                       TCU_FAIL("No suitable depth/stencil format found");
+
+               const vk::VkImageCreateInfo depthStencilCreateInfo =
+               {
+                       vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                                        //      VkStructureType                 sType;
+                       nullptr,                                                                                                                                                        //      const void*                             pNext;
+                       0u,                                                                                                                                                                     //      VkImageCreateFlags              flags;
+                       vk::VK_IMAGE_TYPE_2D,                                                                                                                           //      VkImageType                             imageType;
+                       depthStencilFormat,                                                                                                                                     //      VkFormat                                format;
+                       vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u),                                            //      VkExtent3D                              extent;
+                       1u,                                                                                                                                                                     //      deUint32                                mipLevels;
+                       1u,                                                                                                                                                                     //      deUint32                                arrayLayers;
+                       vk::VK_SAMPLE_COUNT_1_BIT,                                                                                                                      //      VkSampleCountFlagBits   samples;
+                       vk::VK_IMAGE_TILING_OPTIMAL,                                                                                                            //      VkImageTiling                   tiling;
+                       vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,                                                                        //      VkImageUsageFlags               usage;
+                       vk::VK_SHARING_MODE_EXCLUSIVE,                                                                                                          //      VkSharingMode                   sharingMode;
+                       0u,                                                                                                                                                                     //      deUint32                                queueFamilyIndexCount;
+                       nullptr,                                                                                                                                                        //      const deUint32*                 pQueueFamilyIndices;
+                       vk::VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                          //      VkImageLayout                   initialLayout;
+               };
+
+               depthStencilImage.reset(new vk::ImageWithMemory(vkd, device, alloc, depthStencilCreateInfo, vk::MemoryRequirement::Any));
+       }
+
+       // Image views.
+       const auto colorSubresourceRange        = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const auto colorImageView                       = vk::makeImageView(vkd, device, colorImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kColorFormat, colorSubresourceRange);
+
+       vk::Move<vk::VkImageView> depthStencilImageView;
+       if (depthStencilImage)
+       {
+               const auto depthStencilSubresourceRange = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
+               depthStencilImageView = vk::makeImageView(vkd, device, depthStencilImage.get()->get(), vk::VK_IMAGE_VIEW_TYPE_2D, depthStencilFormat, depthStencilSubresourceRange);
+       }
+
+       // Color image buffer.
+       const auto tcuFormat                    = vk::mapVkFormat(kColorFormat);
+       const auto colorImageBufferSize = static_cast<vk::VkDeviceSize>(kTotalPixels * tcuFormat.getPixelSize());
+       const auto colorImageBufferInfo = vk::makeBufferCreateInfo(colorImageBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       vk::BufferWithMemory colorImageBuffer(vkd, device, alloc, colorImageBufferInfo, vk::MemoryRequirement::HostVisible);
+
+       // Vertex buffer.
+       const std::vector<tcu::Vec2> fullScreenQuad =
+       {
+               tcu::Vec2(-1.0f,  1.0f),
+               tcu::Vec2( 1.0f,  1.0f),
+               tcu::Vec2( 1.0f, -1.0f),
+               tcu::Vec2(-1.0f,  1.0f),
+               tcu::Vec2( 1.0f, -1.0f),
+               tcu::Vec2(-1.0f, -1.0f),
+       };
+
+       const auto                              vertexBufferSize        = static_cast<vk::VkDeviceSize>(fullScreenQuad.size() * sizeof(decltype(fullScreenQuad)::value_type));
+       const auto                              vertexBufferInfo        = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+       const vk::VkDeviceSize  vertexBufferOffset      = 0ull;
+       vk::BufferWithMemory    vertexBuffer            (vkd, device, alloc, vertexBufferInfo, vk::MemoryRequirement::HostVisible);
+       const auto&                             vertexBufferAlloc       = vertexBuffer.getAllocation();
+
+       deMemcpy(vertexBufferAlloc.getHostPtr(), fullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
+       vk::flushAlloc(vkd, device, vertexBufferAlloc);
+
+       // Storage buffer.
+       const auto                              storageBufferSize       = static_cast<vk::VkDeviceSize>(kTotalPixels * sizeof(deInt32));
+       const auto                              storageBufferInfo       = vk::makeBufferCreateInfo(storageBufferSize, (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT));
+       vk::BufferWithMemory    storageBuffer           (vkd, device, alloc, storageBufferInfo, vk::MemoryRequirement::HostVisible);
+       const auto&                             storageBufferAlloc      = storageBuffer.getAllocation();
+
+       deMemset(storageBufferAlloc.getHostPtr(), 0, static_cast<size_t>(storageBufferSize));
+       vk::flushAlloc(vkd, device, storageBufferAlloc);
+
+       // Descriptor set layout.
+       vk::DescriptorSetLayoutBuilder layoutBuilder;
+       layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
+       const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
+
+       // Pipeline layout.
+       const auto pipelineLayout = vk::makePipelineLayout(vkd, device, descriptorSetLayout.get());
+
+       // Descriptor pool.
+       vk::DescriptorPoolBuilder poolBuilder;
+       poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+       const auto descriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+
+       // Descriptor set.
+       const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
+
+       // Update descriptor set.
+       vk::DescriptorSetUpdateBuilder  updateBuilder;
+       const auto                                              descriptorBufferInfo = vk::makeDescriptorBufferInfo(storageBuffer.get(), 0u, storageBufferSize);
+       updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo);
+       updateBuilder.update(vkd, device);
+
+       // Render pass.
+       const auto renderPass = vk::makeRenderPass(vkd, device, kColorFormat, depthStencilFormat);
+
+       // Framebuffer.
+       std::vector<vk::VkImageView> imageViews(1u, colorImageView.get());
+       if (depthStencilImage)
+               imageViews.push_back(depthStencilImageView.get());
+
+       const auto framebuffer = vk::makeFramebuffer(vkd, device, renderPass.get(), static_cast<deUint32>(imageViews.size()), imageViews.data(), kFramebufferWidth, kFramebufferHeight);
+
+       // Shader modules.
+       const auto vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
+       const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
+
+       // Vertex input state.
+       const auto vertexBinding        = vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(sizeof(tcu::Vec2)), vk::VK_VERTEX_INPUT_RATE_VERTEX);
+       const auto vertexAttributes     = vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u);
+
+       const vk::VkPipelineVertexInputStateCreateInfo vertexInputInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,  //      VkStructureType                                                         sType;
+               nullptr,                                                                                                                //      const void*                                                                     pNext;
+               0u,                                                                                                                             //      VkPipelineVertexInputStateCreateFlags           flags;
+               1u,                                                                                                                             //      deUint32                                                                        vertexBindingDescriptionCount;
+               &vertexBinding,                                                                                                 //      const VkVertexInputBindingDescription*          pVertexBindingDescriptions;
+               1u,                                                                                                                             //      deUint32                                                                        vertexAttributeDescriptionCount;
+               &vertexAttributes,                                                                                              //      const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions;
+       };
+
+       // Input assembly state.
+       const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,        //      VkStructureType                                                 sType;
+               nullptr,                                                                                                                        //      const void*                                                             pNext;
+               0u,                                                                                                                                     //      VkPipelineInputAssemblyStateCreateFlags flags;
+               vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,                                                        //      VkPrimitiveTopology                                             topology;
+               VK_FALSE,                                                                                                                       //      VkBool32                                                                primitiveRestartEnable;
+       };
+
+       // Viewport state.
+       const auto viewport     = vk::makeViewport(kFramebufferWidth, kFramebufferHeight);
+       const auto scissor      = vk::makeRect2D(kFramebufferWidth, kFramebufferHeight);
+
+       const vk::VkPipelineViewportStateCreateInfo viewportInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,      //      VkStructureType                                         sType;
+               nullptr,                                                                                                        //      const void*                                                     pNext;
+               0u,                                                                                                                     //      VkPipelineViewportStateCreateFlags      flags;
+               1u,                                                                                                                     //      deUint32                                                        viewportCount;
+               &viewport,                                                                                                      //      const VkViewport*                                       pViewports;
+               1u,                                                                                                                     //      deUint32                                                        scissorCount;
+               &scissor,                                                                                                       //      const VkRect2D*                                         pScissors;
+       };
+
+       // Rasterization state.
+       const vk::VkPipelineRasterizationStateCreateInfo rasterizationInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //      VkStructureType                                                 sType;
+               nullptr,                                                                                                                //      const void*                                                             pNext;
+               0u,                                                                                                                             //      VkPipelineRasterizationStateCreateFlags flags;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                depthClampEnable;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                rasterizerDiscardEnable;
+               vk::VK_POLYGON_MODE_FILL,                                                                               //      VkPolygonMode                                                   polygonMode;
+               vk::VK_CULL_MODE_NONE,                                                                                  //      VkCullModeFlags                                                 cullMode;
+               vk::VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                    //      VkFrontFace                                                             frontFace;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                depthBiasEnable;
+               0.0f,                                                                                                                   //      float                                                                   depthBiasConstantFactor;
+               0.0f,                                                                                                                   //      float                                                                   depthBiasClamp;
+               0.0f,                                                                                                                   //      float                                                                   depthBiasSlopeFactor;
+               1.0f,                                                                                                                   //      float                                                                   lineWidth;
+       };
+
+       // Multisample state.
+       const bool                                                                              alphaToCoverageEnable   = (m_params.caseType == CaseType::ALPHA_COVERAGE_BEFORE || m_params.caseType == CaseType::ALPHA_COVERAGE_AFTER);
+       const vk::VkPipelineMultisampleStateCreateInfo  multisampleInfo                 =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,   //      VkStructureType                                                 sType;
+               nullptr,                                                                                                                //      const void*                                                             pNext;
+               0u,                                                                                                                             //      VkPipelineMultisampleStateCreateFlags   flags;
+               vk::VK_SAMPLE_COUNT_1_BIT,                                                                              //      VkSampleCountFlagBits                                   rasterizationSamples;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                sampleShadingEnable;
+               0.0f,                                                                                                                   //      float                                                                   minSampleShading;
+               nullptr,                                                                                                                //      const VkSampleMask*                                             pSampleMask;
+               makeVkBool32(alphaToCoverageEnable),                                                    //      VkBool32                                                                alphaToCoverageEnable;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                alphaToOneEnable;
+       };
+
+       // Depth/stencil state.
+       const auto enableDepthBounds            = makeVkBool32(m_params.caseType == CaseType::DEPTH_BOUNDS);
+       const auto enableDepthStencilTest       = static_cast<bool>(depthStencilImage);
+
+       const auto depthCompareOp                       = ((m_params.caseType == CaseType::DEPTH_NEVER) ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
+       const auto stencilCompareOp                     = ((m_params.caseType == CaseType::STENCIL_NEVER) ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
+       const auto stencilOpState                       = vk::makeStencilOpState(vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, stencilCompareOp, 0xFFu, 0xFFu, 0u);
+
+       const vk::VkPipelineDepthStencilStateCreateInfo depthStencilInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,                                 //      VkStructureType                                                 sType;
+               nullptr,                                                                                                                                                //      const void*                                                             pNext;
+               0u,                                                                                                                                                             //      VkPipelineDepthStencilStateCreateFlags  flags;
+               enableDepthStencilTest,                                                                                                                 //      VkBool32                                                                depthTestEnable;
+               enableDepthStencilTest,                                                                                                                 //      VkBool32                                                                depthWriteEnable;
+               depthCompareOp,                                                                                                                                 //      VkCompareOp                                                             depthCompareOp;
+               enableDepthBounds,                                                                                                                              //      VkBool32                                                                depthBoundsTestEnable;
+               enableDepthStencilTest,                                                                                                                 //      VkBool32                                                                stencilTestEnable;
+               stencilOpState,                                                                                                                                 //      VkStencilOpState                                                front;
+               stencilOpState,                                                                                                                                 //      VkStencilOpState                                                back;
+               (enableDepthBounds ? m_params.depthBoundsParams.get().minDepthBounds : 0.0f),   //      float                                                                   minDepthBounds;
+               (enableDepthBounds ? m_params.depthBoundsParams.get().maxDepthBounds : 1.0f),   //      float                                                                   maxDepthBounds;
+       };
+
+       // Color blend state.
+       const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+       {
+               VK_FALSE,                                               // VkBool32                 blendEnable
+               vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcColorBlendFactor
+               vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstColorBlendFactor
+               vk::VK_BLEND_OP_ADD,                    // VkBlendOp                colorBlendOp
+               vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcAlphaBlendFactor
+               vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstAlphaBlendFactor
+               vk::VK_BLEND_OP_ADD,                    // VkBlendOp                alphaBlendOp
+               vk::VK_COLOR_COMPONENT_R_BIT    // VkColorComponentFlags    colorWriteMask
+               | vk::VK_COLOR_COMPONENT_G_BIT
+               | vk::VK_COLOR_COMPONENT_B_BIT
+               | vk::VK_COLOR_COMPONENT_A_BIT
+       };
+
+       const vk::VkPipelineColorBlendStateCreateInfo colorBlendInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,   //      VkStructureType                                                         sType;
+               nullptr,                                                                                                                //      const void*                                                                     pNext;
+               0u,                                                                                                                             //      VkPipelineColorBlendStateCreateFlags            flags;
+               VK_FALSE,                                                                                                               //      VkBool32                                                                        logicOpEnable;
+               vk::VK_LOGIC_OP_NO_OP,                                                                                  //      VkLogicOp                                                                       logicOp;
+               1u,                                                                                                                             //      deUint32                                                                        attachmentCount;
+               &colorBlendAttachmentState,                                                                             //      const VkPipelineColorBlendAttachmentState*      pAttachments;
+               { .0f, .0f, .0f, .0f },                                                                                 //      float                                                                           blendConstants[4];
+       };
+
+       // Graphics pipeline.
+       const auto graphicsPipeline = vk::makeGraphicsPipeline(
+               vkd, device, pipelineLayout.get(),
+               vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
+               renderPass.get(), 0u,
+               &vertexInputInfo,
+               &inputAssemblyInfo,
+               nullptr,
+               &viewportInfo,
+               &rasterizationInfo,
+               &multisampleInfo,
+               &depthStencilInfo,
+               &colorBlendInfo);
+
+       // Command buffer.
+       const auto cmdPool              = vk::makeCommandPool(vkd, device, queueIndex);
+       const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+       const auto cmdBuffer    = cmdBufferPtr.get();
+
+       // Draw full-screen quad.
+       std::vector<vk::VkClearValue> clearValues;
+       clearValues.push_back(vk::makeClearValueColor(m_params.clearColor));
+       clearValues.push_back(vk::makeClearValueDepthStencil(1.0f, 0u));
+
+       vk::beginCommandBuffer(vkd, cmdBuffer);
+       vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
+       vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
+       vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
+       vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
+       vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(fullScreenQuad.size()), 1u, 0u, 0u);
+       vk::endRenderPass(vkd, cmdBuffer);
+
+       // Image and buffer barriers.
+
+       // Storage buffer frag-write to host-read barrier.
+       const auto storageBufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, storageBuffer.get(), 0u, VK_WHOLE_SIZE);
+
+       // Color image frag-write to transfer-read barrier.
+       const auto colorImageBarrier = vk::makeImageMemoryBarrier(vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSubresourceRange);
+
+       // Color buffer transfer-write to host-read barrier.
+       const auto colorBufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, colorImageBuffer.get(), 0u, VK_WHOLE_SIZE);
+
+       vk::cmdPipelineBufferMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, &storageBufferBarrier);
+       vk::cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, &colorImageBarrier);
+       const auto copyRegion = vk::makeBufferImageCopy(vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u), vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
+       vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImageBuffer.get(), 1u, &copyRegion);
+       vk::cmdPipelineBufferMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, &colorBufferBarrier);
+
+       vk::endCommandBuffer(vkd, cmdBuffer);
+       vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+
+       // Check output.
+       {
+               // Check SSBO contents.
+               vk::invalidateAlloc(vkd, device, storageBufferAlloc);
+               const auto bufferElements = reinterpret_cast<const deInt32*>(storageBufferAlloc.getHostPtr());
+
+               for (deUint32 i = 0; i < kTotalPixels; ++i)
+               {
+                       if (bufferElements[i] != 1)
+                       {
+                               std::ostringstream msg;
+                               msg << "Unexpected value in storage buffer element " << i;
+                               return tcu::TestStatus::fail("Fail: " + msg.str());
+                       }
+               }
+       }
+
+       {
+               // Check color attachment.
+               std::vector<tcu::Vec4> expectedColors(1u, m_params.clearColor);
+               if (!expectClearColor(m_params.caseType))
+                       expectedColors.push_back(m_params.drawColor);
+
+               const auto& colorImageBufferAlloc = colorImageBuffer.getAllocation();
+               vk::invalidateAlloc(vkd, device, colorImageBufferAlloc);
+
+               const auto iWidth       = static_cast<int>(kFramebufferWidth);
+               const auto iHeight      = static_cast<int>(kFramebufferHeight);
+
+               tcu::ConstPixelBufferAccess colorPixels         (tcuFormat, iWidth, iHeight, 1, colorImageBufferAlloc.getHostPtr());
+               std::vector<deUint8>            errorMaskBuffer (kTotalPixels * tcuFormat.getPixelSize(), 0u);
+               tcu::PixelBufferAccess          errorMask               (tcuFormat, iWidth, iHeight, 1, errorMaskBuffer.data());
+               const tcu::Vec4                         green                   (0.0f, 1.0f, 0.0f, 1.0f);
+               const tcu::Vec4                         red                             (1.0f, 0.0f, 0.0f, 1.0f);
+               bool                                            allPixOk                = true;
+
+               for (int i = 0; i < iWidth; ++i)
+               for (int j = 0; j < iHeight; ++j)
+               {
+                       const auto pixel = colorPixels.getPixel(i, j);
+                       const bool pixOk = std::any_of(begin(expectedColors), end(expectedColors), [&pixel](const tcu::Vec4& expected) -> bool { return (pixel == expected); });
+                       errorMask.setPixel((pixOk ? green : red), i, j);
+                       if (!pixOk)
+                               allPixOk = false;
+               }
+
+               if (!allPixOk)
+               {
+                       auto& testLog = m_context.getTestContext().getLog();
+                       testLog << tcu::TestLog::Image("ColorBuffer", "Result color buffer", colorPixels);
+                       testLog << tcu::TestLog::Image("ErrorMask", "Error mask with errors marked in red", errorMask);
+                       return tcu::TestStatus::fail("Fail: color buffer with unexpected values; check logged images");
+               }
+       }
+
+       return tcu::TestStatus::pass("Pass");
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createFragSideEffectsTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> fragSideEffectsGroup(new tcu::TestCaseGroup(testCtx, "frag_side_effects", "Test fragment shader side effects are not removed by optimizations"));
+
+       const tcu::Vec4         kDefaultClearColor                      (0.0f, 0.0f, 0.0f, 1.0f);
+       const tcu::Vec4         kDefaultDrawColor                       (0.0f, 0.0f, 1.0f, 1.0f);
+       const auto                      kDefaultDepthBoundsParams       = tcu::nothing<DepthBoundsParameters>();
+
+       static const struct
+       {
+               bool            colorAtEnd;
+               std::string     name;
+               std::string     desc;
+       } kColorOrders[] =
+       {
+               { false,        "color_at_beginning",   "Fragment shader output assignment at the beginning of the shader"      },
+               { true,         "color_at_end",                 "Fragment shader output assignment at the end of the shader"            },
+       };
+
+       for (int i = 0; i < DE_LENGTH_OF_ARRAY(kColorOrders); ++i)
+       {
+               de::MovePtr<tcu::TestCaseGroup> colorOrderGroup(new tcu::TestCaseGroup(testCtx, kColorOrders[i].name.c_str(), kColorOrders[i].desc.c_str()));
+               const bool colorAtEnd = kColorOrders[i].colorAtEnd;
+
+               {
+                       TestParams params(CaseType::KILL, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "kill", "OpKill after SSBO write", params));
+               }
+               {
+                       TestParams params(CaseType::DEMOTE, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "demote", "OpDemoteToHelperInvocation after SSBO write", params));
+               }
+               {
+                       TestParams params(CaseType::SAMPLE_MASK_BEFORE, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "sample_mask_before", "Set sample mask to zero before SSBO write", params));
+               }
+               {
+                       TestParams params(CaseType::SAMPLE_MASK_AFTER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "sample_mask_after", "Set sample mask to zero after SSBO write", params));
+               }
+               {
+                       TestParams params(CaseType::STENCIL_NEVER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "stencil_never", "SSBO write with stencil test never passes", params));
+               }
+               {
+                       TestParams params(CaseType::DEPTH_NEVER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "depth_never", "SSBO write with depth test never passes", params));
+               }
+               {
+                       const tcu::Vec4 drawColor(kDefaultDrawColor.x(), kDefaultDrawColor.y(), kDefaultDrawColor.z(), 0.0f);
+                       {
+                               TestParams params(CaseType::ALPHA_COVERAGE_BEFORE, kDefaultClearColor, drawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                               colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "alpha_coverage_before", "Enable alpha coverage and draw with alpha zero before SSBO write", params));
+                       }
+                       {
+                               TestParams params(CaseType::ALPHA_COVERAGE_AFTER, kDefaultClearColor, drawColor, colorAtEnd, kDefaultDepthBoundsParams);
+                               colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "alpha_coverage_after", "Enable alpha coverage and draw with alpha zero after SSBO write", params));
+                       }
+               }
+               {
+                       DepthBoundsParameters depthBoundsParams = {0.25f, 0.5f, 0.75f}; // min, max, draw depth.
+                       TestParams params(CaseType::DEPTH_BOUNDS, kDefaultClearColor, kDefaultDrawColor, colorAtEnd, tcu::just(depthBoundsParams));
+                       colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "depth_bounds", "SSBO write with depth bounds test failing", params));
+               }
+
+               fragSideEffectsGroup->addChild(colorOrderGroup.release());
+       }
+
+       return fragSideEffectsGroup.release();
+}
+
+} // rasterization
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.hpp b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationFragShaderSideEffectsTests.hpp
new file mode 100644 (file)
index 0000000..71a22af
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _VKTRASTERIZATIONFRAGSHADERSIDEEFFECTSTESTS_HPP
+#define _VKTRASTERIZATIONFRAGSHADERSIDEEFFECTSTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 The Khronos Group Inc.
+ * Copyright (c) 2020 Valve Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test frag shader side effects are not removed by optimizations.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace rasterization
+{
+
+tcu::TestCaseGroup* createFragSideEffectsTests (tcu::TestContext& testCtx);
+
+} // rasterization
+} // vkt
+
+#endif // _VKTRASTERIZATIONFRAGSHADERSIDEEFFECTSTESTS_HPP
index 69c6be7..2bf4695 100644 (file)
@@ -26,6 +26,7 @@
 #include "vktTestGroupUtil.hpp"
 #include "vktAmberTestCase.hpp"
 #include "vktRasterizationTests.hpp"
+#include "vktRasterizationFragShaderSideEffectsTests.hpp"
 #include "tcuRasterizationVerifier.hpp"
 #include "tcuSurface.hpp"
 #include "tcuRenderTarget.hpp"
@@ -4767,6 +4768,11 @@ void createRasterizationTests (tcu::TestCaseGroup* rasterizationTests)
                        lineContinuity->addChild(testCase);
                }
        }
+
+       // Fragment shader side effects.
+       {
+               rasterizationTests->addChild(createFragSideEffectsTests(testCtx));
+       }
 }
 
 } // anonymous
index 65c12a1..5e3a753 100644 (file)
@@ -500,6 +500,8 @@ bool Context::isDeviceFunctionalitySupported (const std::string& extension) cons
                        return !!getTimelineSemaphoreFeatures().timelineSemaphore;
                if (extension == "VK_EXT_extended_dynamic_state")
                        return !!getExtendedDynamicStateFeaturesEXT().extendedDynamicState;
+               if (extension == "VK_EXT_shader_demote_to_helper_invocation")
+                       return !!getShaderDemoteToHelperInvocationFeaturesEXT().shaderDemoteToHelperInvocation;
 
                return true;
        }
index b6c06b1..096a7d0 100644 (file)
@@ -560579,6 +560579,24 @@ dEQP-VK.rasterization.provoking_vertex.line_strip
 dEQP-VK.rasterization.provoking_vertex.line_strip_with_adjacency
 dEQP-VK.rasterization.line_continuity.line-strip
 dEQP-VK.rasterization.line_continuity.polygon-mode-lines
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_bounds
+dEQP-VK.rasterization.frag_side_effects.color_at_end.kill
+dEQP-VK.rasterization.frag_side_effects.color_at_end.demote
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.sample_mask_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.stencil_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_never
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_before
+dEQP-VK.rasterization.frag_side_effects.color_at_end.alpha_coverage_after
+dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_bounds
 dEQP-VK.clipping.clip_volume.inside.point_list
 dEQP-VK.clipping.clip_volume.inside.line_list
 dEQP-VK.clipping.clip_volume.inside.line_list_with_adjacency