| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2021 The Khronos Group Inc. |
| * Copyright (c) 2021 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 Tests using depth/stencil images as descriptors. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktImageDepthStencilDescriptorTests.hpp" |
| |
| #include "vkBarrierUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkImageWithMemory.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkBufferWithMemory.hpp" |
| |
| #include "tcuMaybe.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deStringUtil.hpp" |
| |
| #include <iterator> |
| #include <vector> |
| #include <sstream> |
| #include <string> |
| |
| namespace vkt |
| { |
| namespace image |
| { |
| |
| namespace |
| { |
| |
| using namespace vk; |
| |
| VkExtent3D getExtent () |
| { |
| return makeExtent3D(8u, 8u, 1u); |
| } |
| |
| VkFormat getColorBufferFormat () |
| { |
| return VK_FORMAT_R8G8B8A8_UNORM; |
| } |
| |
| VkFormat getFloatStorageFormat () |
| { |
| return VK_FORMAT_R32_SFLOAT; |
| } |
| |
| VkFormat getUintStorageFormat () |
| { |
| return VK_FORMAT_R32_UINT; |
| } |
| |
| tcu::Maybe<std::string> layoutExtension (VkImageLayout layout) |
| { |
| std::string extension; |
| |
| switch (layout) |
| { |
| case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: |
| case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: |
| extension = "VK_KHR_maintenance2"; |
| break; |
| case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: |
| case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: |
| // Note: we will not be using separate depth/stencil layouts. There's a separate group of tests for that. |
| extension = "VK_KHR_separate_depth_stencil_layouts"; |
| break; |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| |
| if (!extension.empty()) |
| return tcu::just(extension); |
| return tcu::Nothing; |
| } |
| |
| // Types of access for an image aspect. |
| enum class AspectAccess |
| { |
| NONE = 0, |
| RO = 1, // Different subtypes, see below. |
| RW = 2, // This always means a normal read/write depth/stencil attachment (NOT a storage image). |
| }; |
| |
| std::ostream& operator<< (std::ostream& stream, AspectAccess access) |
| { |
| if (access == AspectAccess::NONE) stream << "none"; |
| else if (access == AspectAccess::RO) stream << "ro"; |
| else if (access == AspectAccess::RW) stream << "rw"; |
| else DE_ASSERT(false); |
| |
| return stream; |
| } |
| |
| // Types of read-only accesses. |
| enum class ReadOnlyAccess |
| { |
| DS_ATTACHMENT = 0, // Depth/stencil attachment but read-only (writes not enabled). |
| INPUT_ATTACHMENT = 1, // Input attachment in the set. |
| SAMPLED = 2, // Sampled image. |
| }; |
| |
| std::ostream& operator<< (std::ostream& stream, ReadOnlyAccess access) |
| { |
| if (access == ReadOnlyAccess::DS_ATTACHMENT) stream << "att"; |
| else if (access == ReadOnlyAccess::INPUT_ATTACHMENT) stream << "ia"; |
| else if (access == ReadOnlyAccess::SAMPLED) stream << "sampled"; |
| else DE_ASSERT(false); |
| |
| return stream; |
| } |
| |
| // A given layout gives different accesses to each aspect. |
| AspectAccess getLegalAccess (VkImageLayout layout, VkImageAspectFlagBits aspect) |
| { |
| DE_ASSERT(aspect == VK_IMAGE_ASPECT_DEPTH_BIT || aspect == VK_IMAGE_ASPECT_STENCIL_BIT); |
| |
| if (layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) |
| return ((aspect == VK_IMAGE_ASPECT_STENCIL_BIT) ? AspectAccess::RW : AspectAccess::RO); |
| else if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) |
| return ((aspect == VK_IMAGE_ASPECT_DEPTH_BIT) ? AspectAccess::RW : AspectAccess::RO); |
| else if (layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL) |
| return ((aspect == VK_IMAGE_ASPECT_DEPTH_BIT) ? AspectAccess::RO : AspectAccess::NONE); |
| else if (layout == VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL) |
| return ((aspect == VK_IMAGE_ASPECT_STENCIL_BIT) ? AspectAccess::RO : AspectAccess::NONE); |
| |
| DE_ASSERT(false); |
| return AspectAccess::NONE; // Unreachable. |
| } |
| |
| using ROAccessVec = std::vector<ReadOnlyAccess>; |
| |
| std::ostream& operator<< (std::ostream& stream, const ROAccessVec& vec) |
| { |
| for (size_t i = 0u; i < vec.size(); ++i) |
| stream << ((i > 0u) ? "_" : "") << vec[i]; |
| return stream; |
| } |
| |
| // We cannot access depth/stencil images both as a depth/stencil attachment and an input attachment at the same time if they have |
| // both aspects, because input attachments can only have one aspect. |
| bool incompatibleInputAttachmentAccess (AspectAccess depthAccess, const ROAccessVec* depthROAccesses, AspectAccess stencilAccess, const ROAccessVec* stencilROAccesses) |
| { |
| const bool depthAsDSAttachment = (depthAccess == AspectAccess::RW || (depthAccess == AspectAccess::RO && de::contains(begin(*depthROAccesses), end(*depthROAccesses), ReadOnlyAccess::DS_ATTACHMENT))); |
| const bool stencilAsDSAttachment = (stencilAccess == AspectAccess::RW || (stencilAccess == AspectAccess::RO && de::contains(begin(*stencilROAccesses), end(*stencilROAccesses), ReadOnlyAccess::DS_ATTACHMENT))); |
| const bool depthAsInputAttachment = (depthAccess == AspectAccess::RO && de::contains(begin(*depthROAccesses), end(*depthROAccesses), ReadOnlyAccess::INPUT_ATTACHMENT)); |
| const bool stencilAsInputAttachment = (stencilAccess == AspectAccess::RO && de::contains(begin(*stencilROAccesses), end(*stencilROAccesses), ReadOnlyAccess::INPUT_ATTACHMENT)); |
| |
| return ((depthAsDSAttachment && stencilAsInputAttachment) || (stencilAsDSAttachment && depthAsInputAttachment)); |
| } |
| |
| VkImageUsageFlags getReadOnlyUsageFlags (const ROAccessVec& readOnlyAccesses) |
| { |
| VkImageUsageFlags usageFlags = 0u; |
| |
| for (const auto& access : readOnlyAccesses) |
| { |
| if (access == ReadOnlyAccess::DS_ATTACHMENT) |
| usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| else if (access == ReadOnlyAccess::INPUT_ATTACHMENT) |
| usageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
| else if (access == ReadOnlyAccess::SAMPLED) |
| usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; |
| else |
| DE_ASSERT(false); |
| } |
| |
| return usageFlags; |
| } |
| |
| // Resources needed for an aspect that will be used as a descriptor in shaders (sampled or input attachment). |
| struct InputOutputDescriptor |
| { |
| uint32_t binding; |
| tcu::Maybe<uint32_t> inputAttachmentIndex; |
| VkImageAspectFlagBits aspect; |
| }; |
| |
| using IODescVec = std::vector<InputOutputDescriptor>; |
| |
| // Test parameters. |
| struct TestParams |
| { |
| VkFormat format; // Image format. |
| VkImageLayout layout; // Layout being tested. |
| AspectAccess depthAccess; // Type of access that will be used for depth (must be legal). |
| AspectAccess stencilAccess; // Type of access that will be used for stencil (must be legal). |
| |
| tcu::Maybe<ROAccessVec> depthROAccesses; // Types of read-only accesses for depth (used when depthAccess is RO). |
| tcu::Maybe<ROAccessVec> stencilROAccesses; // Types of read-only accesses for stencil (used when stencilAccess is RO). |
| |
| VkImageUsageFlags getUsageFlags () const; |
| |
| // Get a list of descriptors needed according to the given test parameters. |
| IODescVec getDescriptors () const; |
| |
| // Does this case need a depth/stencil attachment? |
| bool dsAttachmentNeeded () const; |
| |
| // Does this case use the depth aspect as an input attachment? |
| bool depthAsInputAttachment () const; |
| |
| // Does this case use the stencil aspect as an input attachment? |
| bool stencilAsInputAttachment () const; |
| |
| // Does this case need an input attachment? |
| bool inputAttachmentNeeded () const; |
| |
| // Does this case need a depth/stencil attachment as a depth buffer? |
| bool depthBufferNeeded () const; |
| |
| // Does this case need the pipeline depth test enabled? |
| bool needsDepthTest () const; |
| |
| // Does this case need the stencil test enabled? |
| bool needsStencilTest () const; |
| }; |
| |
| VkImageUsageFlags TestParams::getUsageFlags () const |
| { |
| VkImageUsageFlags usageFlags = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| |
| if (depthAccess == AspectAccess::RW || stencilAccess == AspectAccess::RW) |
| usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| |
| if (depthAccess == AspectAccess::RO) |
| { |
| DE_ASSERT(static_cast<bool>(depthROAccesses)); |
| usageFlags |= getReadOnlyUsageFlags(*depthROAccesses); |
| } |
| |
| if (stencilAccess == AspectAccess::RO) |
| { |
| DE_ASSERT(static_cast<bool>(stencilROAccesses)); |
| usageFlags |= getReadOnlyUsageFlags(*stencilROAccesses); |
| } |
| |
| return usageFlags; |
| } |
| |
| void addDescriptors (IODescVec& descriptors, uint32_t& inputAttachmentCount, const ROAccessVec& accesses, VkImageAspectFlagBits aspect) |
| { |
| for (const auto& access : accesses) |
| { |
| // Get a new binding number and a new input attachment index if needed, then append the new descriptor to the list if |
| // appropriate. |
| |
| InputOutputDescriptor descriptor = |
| { |
| static_cast<uint32_t>(descriptors.size()), // uint32_t binding; |
| tcu::Nothing, // tcu::Maybe<uint32_t> inputAttachmentIndex; |
| aspect, // VkImageAspectFlagBits aspect; |
| }; |
| |
| if (access == ReadOnlyAccess::INPUT_ATTACHMENT) |
| descriptor.inputAttachmentIndex = tcu::just(inputAttachmentCount++); |
| |
| if (access == ReadOnlyAccess::INPUT_ATTACHMENT || access == ReadOnlyAccess::SAMPLED) |
| descriptors.push_back(descriptor); |
| } |
| } |
| |
| IODescVec TestParams::getDescriptors () const |
| { |
| IODescVec descriptors; |
| uint32_t inputAttachmentCount = 0u; |
| |
| if (static_cast<bool>(depthROAccesses)) |
| addDescriptors(descriptors, inputAttachmentCount, *depthROAccesses, VK_IMAGE_ASPECT_DEPTH_BIT); |
| |
| if (static_cast<bool>(stencilROAccesses)) |
| addDescriptors(descriptors, inputAttachmentCount, *stencilROAccesses, VK_IMAGE_ASPECT_STENCIL_BIT); |
| |
| return descriptors; |
| } |
| |
| bool TestParams::dsAttachmentNeeded () const |
| { |
| // The depth/stencil attachment is needed if the image is going to be used as a depth/stencil attachment or an input attachment. |
| return (inputAttachmentNeeded() || depthBufferNeeded()); |
| } |
| |
| bool TestParams::depthAsInputAttachment () const |
| { |
| return (depthAccess == AspectAccess::RO && de::contains(begin(*depthROAccesses), end(*depthROAccesses), ReadOnlyAccess::INPUT_ATTACHMENT)); |
| } |
| |
| bool TestParams::stencilAsInputAttachment () const |
| { |
| return (stencilAccess == AspectAccess::RO && de::contains(begin(*stencilROAccesses), end(*stencilROAccesses), ReadOnlyAccess::INPUT_ATTACHMENT)); |
| } |
| |
| bool TestParams::inputAttachmentNeeded () const |
| { |
| // An input attachment is needed if any of the depth or stencil aspects include a read-only access as an input attachment. |
| return (depthAsInputAttachment() || stencilAsInputAttachment()); |
| } |
| |
| bool TestParams::depthBufferNeeded () const |
| { |
| // The depth buffer is needed if any of the depth or stencil aspects include a read-write or read-only DS access. |
| return (needsDepthTest() || needsStencilTest()); |
| } |
| |
| bool TestParams::needsDepthTest () const |
| { |
| // The depth test is needed if the depth aspect includes a read-write or read-only DS access. |
| return (depthAccess == AspectAccess::RW || (depthAccess == AspectAccess::RO && de::contains(begin(*depthROAccesses), end(*depthROAccesses), ReadOnlyAccess::DS_ATTACHMENT))); |
| } |
| |
| bool TestParams::needsStencilTest () const |
| { |
| // The stencil test is needed if the stencil aspect includes a read-write or read-only DS access. |
| return (stencilAccess == AspectAccess::RW || (stencilAccess == AspectAccess::RO && de::contains(begin(*stencilROAccesses), end(*stencilROAccesses), ReadOnlyAccess::DS_ATTACHMENT))); |
| } |
| |
| class DepthStencilDescriptorCase : public vkt::TestCase |
| { |
| public: |
| DepthStencilDescriptorCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params); |
| virtual ~DepthStencilDescriptorCase (void) {} |
| |
| void checkSupport (Context& context) const override; |
| TestInstance* createInstance (Context& context) const override; |
| void initPrograms (vk::SourceCollections& programCollection) const override; |
| |
| protected: |
| TestParams m_params; |
| }; |
| |
| class DepthStencilDescriptorInstance : public vkt::TestInstance |
| { |
| public: |
| DepthStencilDescriptorInstance (Context& context, const TestParams& params); |
| virtual ~DepthStencilDescriptorInstance (void) {} |
| |
| tcu::TestStatus iterate() override; |
| |
| protected: |
| // Must match the shaders. |
| struct PushConstantData |
| { |
| float colorR; |
| float colorG; |
| float colorB; |
| float colorA; |
| float depth; |
| |
| PushConstantData () |
| : colorR (0.0f) |
| , colorG (0.0f) |
| , colorB (0.0f) |
| , colorA (0.0f) |
| , depth (0.0f) |
| {} |
| |
| PushConstantData (const tcu::Vec4& color, float depth_) |
| : colorR (color.x()) |
| , colorG (color.y()) |
| , colorB (color.z()) |
| , colorA (color.w()) |
| , depth (depth_) |
| {} |
| }; |
| |
| TestParams m_params; |
| }; |
| |
| DepthStencilDescriptorCase::DepthStencilDescriptorCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| {} |
| |
| void DepthStencilDescriptorCase::checkSupport (Context& context) const |
| { |
| context.requireDeviceFunctionality("VK_KHR_create_renderpass2"); |
| |
| const auto requiredExtension = layoutExtension(m_params.layout); |
| if (requiredExtension) |
| context.requireDeviceFunctionality(*requiredExtension); |
| |
| // Check format support. |
| const auto& vki = context.getInstanceInterface(); |
| const auto physDev = context.getPhysicalDevice(); |
| const auto imgType = VK_IMAGE_TYPE_2D; |
| const auto tiling = VK_IMAGE_TILING_OPTIMAL; |
| const auto usage = m_params.getUsageFlags(); |
| |
| VkImageFormatProperties formatProperties; |
| const auto res = vki.getPhysicalDeviceImageFormatProperties(physDev, m_params.format, imgType, tiling, usage, 0u, &formatProperties); |
| if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| TCU_THROW(NotSupportedError, "Format does not support required properties"); |
| else if (res != VK_SUCCESS) |
| TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned " + de::toString(res)); |
| } |
| |
| TestInstance* DepthStencilDescriptorCase::createInstance (Context& context) const |
| { |
| return new DepthStencilDescriptorInstance(context, m_params); |
| } |
| |
| void DepthStencilDescriptorCase::initPrograms (vk::SourceCollections& programCollection) const |
| { |
| std::ostringstream vert; |
| vert |
| << "#version 450\n" |
| << "\n" |
| << "layout(push_constant, std430) uniform PushConstantBlock {\n" |
| << " float colorR;\n" |
| << " float colorG;\n" |
| << " float colorB;\n" |
| << " float colorA;\n" |
| << " float depth;\n" |
| << "} pc;\n" |
| << "\n" |
| << "vec2 vertexPositions[3] = vec2[](\n" |
| << " vec2(-1.0, -1.0),\n" |
| << " vec2(-1.0, 3.0),\n" |
| << " vec2( 3.0, -1.0));\n" |
| << "\n" |
| << "void main () {\n" |
| << " gl_Position = vec4(vertexPositions[gl_VertexIndex], pc.depth, 1.0);\n" |
| << "}\n" |
| ; |
| programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); |
| |
| // When any of the image aspects is going to be used as an input attachment or sampled image, we need an input descriptor and an |
| // output descriptor to verify reading from it. |
| std::ostringstream descriptorsDecl; |
| std::ostringstream descriptorsSideEffects; |
| const auto descriptors = m_params.getDescriptors(); |
| |
| // Samplers set (set number 2). |
| descriptorsDecl |
| << "layout (set=2, binding=0) uniform sampler globalSampler;\n" // Sampler with float border color (depth). |
| << "layout (set=2, binding=1) uniform sampler uglobalSampler;\n" // Sampler with int border color (stencil). |
| ; |
| |
| for (const auto& descriptor : descriptors) |
| { |
| const auto prefix = ((descriptor.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) ? "u" : ""); |
| const auto suffix = ((descriptor.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) ? "ui" : "f"); |
| std::ostringstream loadOp; |
| |
| // Input descriptor declaration. |
| if (static_cast<bool>(descriptor.inputAttachmentIndex)) |
| { |
| const auto& iaIndex = *descriptor.inputAttachmentIndex; |
| descriptorsDecl << "layout (input_attachment_index=" << iaIndex << ", set=0, binding=" << descriptor.binding << ") uniform " << prefix << "subpassInput attachment" << descriptor.binding << ";\n"; |
| loadOp << "subpassLoad(attachment" << descriptor.binding << ")"; |
| } |
| else |
| { |
| descriptorsDecl << "layout (set=0, binding=" << descriptor.binding << ") uniform " << prefix << "texture2D sampledImage" << descriptor.binding << ";\n"; |
| loadOp << "texture(" << prefix << "sampler2D(sampledImage" << descriptor.binding << ", " << prefix << "globalSampler), gl_FragCoord.xy)"; // This needs a sampler with unnormalizedCoordinates == VK_TRUE. |
| } |
| |
| // Output descriptor declaration (output descriptors in set 1). |
| descriptorsDecl << "layout (r32" << suffix << ", set=1, binding=" << descriptor.binding << ") uniform " << prefix << "image2D storage" << descriptor.binding << ";\n"; |
| |
| // The corresponding side effect. |
| descriptorsSideEffects << " imageStore(storage" << descriptor.binding << ", ivec2(gl_FragCoord.xy), " << loadOp.str() << ");\n"; |
| } |
| |
| std::ostringstream frag; |
| frag |
| << "#version 450\n" |
| << "\n" |
| << "layout(location=0) out vec4 outColor;\n" |
| << "layout(push_constant, std430) uniform PushConstantBlock {\n" |
| << " float colorR;\n" |
| << " float colorG;\n" |
| << " float colorB;\n" |
| << " float colorA;\n" |
| << " float depth;\n" |
| << "} pc;\n" |
| << "\n" |
| << descriptorsDecl.str() |
| << "\n" |
| << "void main () {\n" |
| << descriptorsSideEffects.str() |
| << " outColor = vec4(pc.colorR, pc.colorG, pc.colorB, pc.colorA);\n" |
| << "}\n" |
| ; |
| |
| programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); |
| } |
| |
| DepthStencilDescriptorInstance::DepthStencilDescriptorInstance (Context& context, const TestParams& params) |
| : vkt::TestInstance (context) |
| , m_params (params) |
| {} |
| |
| VkFormat getAspectStorageFormat (VkImageAspectFlagBits aspect) |
| { |
| return ((aspect == VK_IMAGE_ASPECT_DEPTH_BIT) ? getFloatStorageFormat() : getUintStorageFormat()); |
| } |
| |
| VkDeviceSize getCopyBufferSize (const tcu::TextureFormat& format, const VkExtent3D& extent) |
| { |
| return static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(format)) * extent.width * extent.height * extent.depth); |
| } |
| |
| tcu::TestStatus DepthStencilDescriptorInstance::iterate () |
| { |
| const auto& vkd = m_context.getDeviceInterface(); |
| const auto device = m_context.getDevice(); |
| auto& alloc = m_context.getDefaultAllocator(); |
| const auto qIndex = m_context.getUniversalQueueFamilyIndex(); |
| const auto queue = m_context.getUniversalQueue(); |
| const auto extent = getExtent(); |
| const auto usage = m_params.getUsageFlags(); |
| const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| const auto colorFormat = getColorBufferFormat(); |
| const auto tcuColorFormat = mapVkFormat(colorFormat); |
| const auto storageUsage = (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| const auto stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
| const auto tcuFormat = mapVkFormat(m_params.format); |
| const auto hasDepth = tcu::hasDepthComponent(tcuFormat.order); |
| const auto hasStencil = tcu::hasStencilComponent(tcuFormat.order); |
| const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| const auto outputImgLayout = VK_IMAGE_LAYOUT_GENERAL; |
| const auto colorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| // Copy formats. |
| const auto tcuDepthFormat = (hasDepth ? getDepthCopyFormat(m_params.format) : tcu::TextureFormat()); |
| const auto tcuStencilFormat = (hasStencil ? getStencilCopyFormat(m_params.format) : tcu::TextureFormat()); |
| |
| // These must match the depth test configuration when enabled. |
| const float depthClearValue = 0.5f; |
| const float depthFailValue = 1.0f; |
| const float depthPassValue = 0.0f; |
| |
| // These must match the stencil test configuration when enabled. |
| const uint32_t stencilClearVal = 100u; |
| const uint32_t stencilFailVal = 200u; |
| const uint32_t stencilPassVal = 10u; |
| |
| // For the color buffer. |
| const tcu::Vec4 colorClearVal (0.0f, 0.0f, 0.0f, 1.0f); |
| const tcu::Vec4 colorFailVal (1.0f, 0.0f, 0.0f, 1.0f); |
| const tcu::Vec4 colorPassVal (0.0f, 1.0f, 0.0f, 1.0f); |
| |
| // Will the test update the depth/stencil buffer? |
| const auto stencilWrites = (m_params.stencilAccess == AspectAccess::RW); |
| const auto depthWrites = (m_params.depthAccess == AspectAccess::RW); |
| |
| // Create color attachment. |
| const VkImageCreateInfo colorBufferInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| colorFormat, // VkFormat format; |
| extent, // VkExtent3D extent; |
| 1u, // uint32_t mipLevels; |
| 1u, // uint32_t arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| colorUsage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // uint32_t queueFamilyIndexCount; |
| nullptr, // const uint32_t* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| ImageWithMemory colorBuffer (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any); |
| const auto colorView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR); |
| |
| // Create depth/stencil image. |
| const VkImageCreateInfo dsImageInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| m_params.format, // VkFormat format; |
| extent, // VkExtent3D extent; |
| 1u, // uint32_t mipLevels; |
| 1u, // uint32_t arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // uint32_t queueFamilyIndexCount; |
| nullptr, // const uint32_t* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| ImageWithMemory dsImage(vkd, device, alloc, dsImageInfo, MemoryRequirement::Any); |
| const auto depthStencilSRR = makeImageSubresourceRange(getImageAspectFlags(tcuFormat), 0u, 1u, 0u, 1u); |
| const auto depthSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u); |
| const auto stencilSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u); |
| const auto dsImageView = makeImageView(vkd, device, dsImage.get(), VK_IMAGE_VIEW_TYPE_2D, m_params.format, depthStencilSRR); |
| |
| Move<VkImageView> depthOnlyView; |
| Move<VkImageView> stencilOnlyView; |
| |
| if (hasDepth) |
| depthOnlyView = makeImageView(vkd, device, dsImage.get(), VK_IMAGE_VIEW_TYPE_2D, m_params.format, depthSRR); |
| |
| if (hasStencil) |
| stencilOnlyView = makeImageView(vkd, device, dsImage.get(), VK_IMAGE_VIEW_TYPE_2D, m_params.format, stencilSRR); |
| |
| // Get expected descriptors and create output images for them. |
| const auto descriptors = m_params.getDescriptors(); |
| |
| std::vector<de::MovePtr<ImageWithMemory>> outputImages; |
| std::vector<Move<VkImageView>> outputImageViews; |
| |
| outputImages.reserve(descriptors.size()); |
| outputImageViews.reserve(descriptors.size()); |
| |
| for (const auto& desc : descriptors) |
| { |
| // Floating point images to copy the depth aspect and unsigned int images to copy the stencil aspect. |
| const auto imageFormat = getAspectStorageFormat(desc.aspect); |
| |
| const VkImageCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| imageFormat, // VkFormat format; |
| extent, // VkExtent3D extent; |
| 1u, // uint32_t mipLevels; |
| 1u, // uint32_t arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| storageUsage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // uint32_t queueFamilyIndexCount; |
| nullptr, // const uint32_t* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| outputImages.push_back(de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, alloc, createInfo, MemoryRequirement::Any))); |
| outputImageViews.push_back(makeImageView(vkd, device, outputImages.back()->get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR)); |
| } |
| |
| // Create samplers. |
| Move<VkSampler> samplerFloat; |
| Move<VkSampler> samplerInt; |
| { |
| VkSamplerCreateInfo samplerCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkSamplerCreateFlags flags; |
| VK_FILTER_NEAREST, // VkFilter magFilter; |
| VK_FILTER_NEAREST, // VkFilter minFilter; |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW; |
| 0.0f, // float mipLodBias; |
| VK_FALSE, // VkBool32 anisotropyEnable; |
| 0.0f, // float maxAnisotropy; |
| VK_FALSE, // VkBool32 compareEnable; |
| VK_COMPARE_OP_LAST, // VkCompareOp compareOp; |
| 0.0f, // float minLod; |
| 0.0f, // float maxLod; |
| VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, // VkBorderColor borderColor; |
| VK_TRUE, // VkBool32 unnormalizedCoordinates; |
| }; |
| // Note the samplers are created with unnormalizedCoordinates as per how they are used in shader code. |
| samplerFloat = createSampler(vkd, device, &samplerCreateInfo); |
| |
| samplerCreateInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; |
| samplerInt = createSampler(vkd, device, &samplerCreateInfo); |
| } |
| |
| // Create input and output descriptor set layouts. |
| Move<VkDescriptorSetLayout> inputSetLayout; |
| Move<VkDescriptorSetLayout> outputSetLayout; |
| Move<VkDescriptorSetLayout> samplerSetLayout; |
| |
| { |
| DescriptorSetLayoutBuilder inputLayoutBuilder; |
| for (const auto& desc : descriptors) |
| { |
| if (static_cast<bool>(desc.inputAttachmentIndex)) |
| inputLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, stageFlags); |
| else |
| inputLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags); |
| } |
| inputSetLayout = inputLayoutBuilder.build(vkd, device); |
| } |
| { |
| DescriptorSetLayoutBuilder outputLayoutBuilder; |
| for (size_t i = 0; i < descriptors.size(); ++i) |
| outputLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stageFlags); |
| outputSetLayout = outputLayoutBuilder.build(vkd, device); |
| } |
| { |
| DescriptorSetLayoutBuilder samplerLayoutBuilder; |
| samplerLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, stageFlags); |
| samplerLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, stageFlags); |
| samplerSetLayout = samplerLayoutBuilder.build(vkd, device); |
| } |
| |
| const std::vector<VkDescriptorSetLayout> setLayouts = { inputSetLayout.get(), outputSetLayout.get(), samplerSetLayout.get() }; |
| |
| // Descriptor pool and descriptor sets. |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSet> inputSet; |
| Move<VkDescriptorSet> outputSet; |
| Move<VkDescriptorSet> samplerSet; |
| { |
| DescriptorPoolBuilder poolBuilder; |
| |
| // Input descriptors. |
| for (const auto& desc : descriptors) |
| { |
| if (static_cast<bool>(desc.inputAttachmentIndex)) |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT); |
| else |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| } |
| |
| // Output descriptors. |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, static_cast<uint32_t>(descriptors.size())); |
| |
| // Global samplers. |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 2u); |
| |
| descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, static_cast<uint32_t>(setLayouts.size())); |
| } |
| |
| inputSet = makeDescriptorSet(vkd, device, descriptorPool.get(), inputSetLayout.get()); |
| outputSet = makeDescriptorSet(vkd, device, descriptorPool.get(), outputSetLayout.get()); |
| samplerSet = makeDescriptorSet(vkd, device, descriptorPool.get(), samplerSetLayout.get()); |
| |
| const std::vector<VkDescriptorSet> descriptorSets = { inputSet.get(), outputSet.get(), samplerSet.get() }; |
| |
| // Update descriptor sets. |
| { |
| DescriptorSetUpdateBuilder inputUpdateBuilder; |
| DescriptorSetUpdateBuilder outputUpdateBuilder; |
| DescriptorSetUpdateBuilder samplerUpdateBuilder; |
| |
| std::vector<VkDescriptorImageInfo> inputImgInfos; |
| std::vector<VkDescriptorImageInfo> outputImgInfos; |
| std::vector<VkDescriptorImageInfo> samplerImgInfos; |
| |
| // Make sure addresses are stable (pushing elements back while taking their addresses). |
| inputImgInfos.reserve(descriptors.size()); |
| outputImgInfos.reserve(descriptors.size()); |
| samplerImgInfos.reserve(2u); |
| |
| for (size_t descriptorIdx = 0u; descriptorIdx < descriptors.size(); ++descriptorIdx) |
| { |
| const auto& desc = descriptors[descriptorIdx]; |
| const auto isIA = static_cast<bool>(desc.inputAttachmentIndex); |
| const auto location = DescriptorSetUpdateBuilder::Location::binding(desc.binding); |
| |
| // Input descriptors. |
| const auto inType = (isIA ? VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| const auto view = ((desc.aspect == VK_IMAGE_ASPECT_DEPTH_BIT) ? depthOnlyView.get() : stencilOnlyView.get()); |
| inputImgInfos.push_back(makeDescriptorImageInfo(DE_NULL, view, m_params.layout)); |
| inputUpdateBuilder.writeSingle(inputSet.get(), location, inType, &inputImgInfos.back()); |
| |
| // Output descriptors. |
| outputImgInfos.push_back(makeDescriptorImageInfo(DE_NULL, outputImageViews[descriptorIdx].get(), outputImgLayout)); |
| outputUpdateBuilder.writeSingle(outputSet.get(), location, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &outputImgInfos.back()); |
| } |
| |
| inputUpdateBuilder.update(vkd, device); |
| outputUpdateBuilder.update(vkd, device); |
| |
| // Samplers. |
| samplerImgInfos.push_back(makeDescriptorImageInfo(samplerFloat.get(), DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED)); |
| samplerUpdateBuilder.writeSingle(samplerSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_SAMPLER, &samplerImgInfos.back()); |
| |
| samplerImgInfos.push_back(makeDescriptorImageInfo(samplerInt.get(), DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED)); |
| samplerUpdateBuilder.writeSingle(samplerSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_SAMPLER, &samplerImgInfos.back()); |
| |
| samplerUpdateBuilder.update(vkd, device); |
| } |
| |
| PushConstantData pcData; |
| const auto pcStages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); |
| const auto pcSize = static_cast<uint32_t>(sizeof(pcData)); |
| const auto pcRange = makePushConstantRange(pcStages, 0u, pcSize); |
| |
| // Pipeline layout. |
| const auto pipelineLayout = makePipelineLayout(vkd, device, static_cast<uint32_t>(setLayouts.size()), de::dataOrNull(setLayouts), 1u, &pcRange); |
| |
| // Render pass. |
| Move<VkRenderPass> renderPass; |
| |
| { |
| std::vector<VkAttachmentDescription2> attachmentDescriptions; |
| std::vector<VkAttachmentReference2> attachmentReferences; |
| |
| const VkAttachmentDescription2 colorAttachmentDesc = |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkAttachmentDescriptionFlags flags; |
| colorFormat, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_LOAD, // 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; |
| colorLayout, // VkImageLayout initialLayout; |
| colorLayout, // VkImageLayout finalLayout; |
| }; |
| attachmentDescriptions.push_back(colorAttachmentDesc); |
| |
| const VkAttachmentReference2 colorAttachmentRef = |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // uint32_t attachment; |
| colorLayout, // VkImageLayout layout; |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| }; |
| attachmentReferences.push_back(colorAttachmentRef); |
| |
| const auto needsIA = m_params.inputAttachmentNeeded(); |
| const auto needsDepthBuffer = m_params.depthBufferNeeded(); |
| DE_ASSERT(!(needsIA && needsDepthBuffer)); |
| |
| if (m_params.dsAttachmentNeeded()) |
| { |
| const VkAttachmentDescription2 dsAttachmentDesc = |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, |
| nullptr, |
| 0u, |
| m_params.format, |
| VK_SAMPLE_COUNT_1_BIT, |
| (hasDepth ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), |
| ((hasDepth && depthWrites) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE), |
| (hasStencil ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE), |
| ((hasStencil && stencilWrites) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE), |
| m_params.layout, |
| m_params.layout, |
| }; |
| attachmentDescriptions.push_back(dsAttachmentDesc); |
| |
| const VkAttachmentReference2 dsAttachmentRef = |
| { |
| VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 1u, // uint32_t attachment; |
| m_params.layout, // VkImageLayout layout; |
| // VkImageAspectFlags aspectMask; |
| ( (m_params.depthAsInputAttachment() ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) : 0u) |
| | (m_params.stencilAsInputAttachment() ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT) : 0u)), |
| }; |
| |
| attachmentReferences.push_back(dsAttachmentRef); |
| } |
| |
| const VkSubpassDescription2 subpassDesc = |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkSubpassDescriptionFlags flags; |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; |
| 0u, // uint32_t viewMask; |
| (needsIA ? 1u : 0u), // uint32_t inputAttachmentCount; |
| (needsIA ? &attachmentReferences.at(1) : nullptr), // const VkAttachmentReference* pInputAttachments; |
| 1u, // uint32_t colorAttachmentCount; |
| &attachmentReferences.at(0), // const VkAttachmentReference* pColorAttachments; |
| nullptr, // const VkAttachmentReference* pResolveAttachments; |
| (needsDepthBuffer ? &attachmentReferences.at(1) : nullptr), // const VkAttachmentReference* pDepthStencilAttachment; |
| 0u, // uint32_t preserveAttachmentCount; |
| nullptr, // const uint32_t* pPreserveAttachments; |
| }; |
| |
| const VkRenderPassCreateInfo2 renderPassCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkRenderPassCreateFlags flags; |
| static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount; |
| de::dataOrNull(attachmentDescriptions), // const VkAttachmentDescription* pAttachments; |
| 1u, // uint32_t subpassCount; |
| &subpassDesc, // const VkSubpassDescription* pSubpasses; |
| 0u, // uint32_t dependencyCount; |
| nullptr, // const VkSubpassDependency* pDependencies; |
| 0u, // uint32_t correlatedViewMaskCount; |
| nullptr, // const uint32_t* pCorrelatedViewMasks; |
| }; |
| renderPass = createRenderPass2(vkd, device, &renderPassCreateInfo); |
| } |
| |
| // Framebuffer. |
| std::vector<VkImageView> framebufferViews; |
| |
| framebufferViews.push_back(colorView.get()); |
| if (m_params.dsAttachmentNeeded()) |
| framebufferViews.push_back(dsImageView.get()); |
| |
| const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), static_cast<uint32_t>(framebufferViews.size()), de::dataOrNull(framebufferViews), extent.width, extent.height); |
| |
| // Pipeline. |
| std::vector<Move<VkPipeline>> graphicsPipelines; |
| { |
| const auto vertModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u); |
| const auto fragModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u); |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputInfo = initVulkanStructure(); |
| VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = initVulkanStructure(); |
| VkPipelineViewportStateCreateInfo viewportInfo = initVulkanStructure(); |
| VkPipelineRasterizationStateCreateInfo rasterizationInfo = initVulkanStructure(); |
| VkPipelineMultisampleStateCreateInfo multisampleInfo = initVulkanStructure(); |
| VkPipelineDepthStencilStateCreateInfo dsStateInfo = initVulkanStructure(); |
| VkPipelineColorBlendStateCreateInfo colorBlendInfo = initVulkanStructure(); |
| VkPipelineColorBlendAttachmentState colorBlendAttState = {}; |
| |
| // Topology. |
| inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; |
| |
| // Viewports and scissors. |
| const auto viewport = makeViewport(extent); |
| const auto scissor = makeRect2D(extent); |
| viewportInfo.viewportCount = 1u; |
| viewportInfo.pViewports = &viewport; |
| viewportInfo.scissorCount = 1u; |
| viewportInfo.pScissors = &scissor; |
| |
| // Line width. |
| rasterizationInfo.lineWidth = 1.0f; |
| |
| // Multisample state. |
| multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |
| |
| // Depth/stencil state. This depends on the test parameters. |
| if (m_params.needsDepthTest()) |
| dsStateInfo.depthTestEnable = VK_TRUE; |
| if (depthWrites) |
| dsStateInfo.depthWriteEnable = VK_TRUE; |
| dsStateInfo.depthCompareOp = VK_COMPARE_OP_LESS; |
| if (m_params.needsStencilTest()) |
| dsStateInfo.stencilTestEnable = VK_TRUE; |
| |
| const auto stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP, // failOp |
| (stencilWrites ? VK_STENCIL_OP_REPLACE : VK_STENCIL_OP_KEEP), // passOp |
| VK_STENCIL_OP_KEEP, // depthFailOp |
| VK_COMPARE_OP_LESS, // compareOp |
| 0xFFu, // compareMask |
| (stencilWrites ? 0xFFu : 0u), // writeMask |
| stencilFailVal); // reference |
| dsStateInfo.front = stencilOpState; |
| dsStateInfo.back = stencilOpState; |
| |
| colorBlendAttState.colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); |
| colorBlendAttState.blendEnable = VK_FALSE; |
| colorBlendInfo.attachmentCount = 1u; |
| colorBlendInfo.pAttachments = &colorBlendAttState; |
| |
| graphicsPipelines.push_back(makeGraphicsPipeline(vkd, device, pipelineLayout.get(), |
| vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(), // Shader modules. |
| renderPass.get(), 0u /*subpass*/, |
| &vertexInputInfo, &inputAssemblyInfo, nullptr, &viewportInfo, &rasterizationInfo, &multisampleInfo, &dsStateInfo, &colorBlendInfo, nullptr)); |
| |
| // When the stencil test is enabled, we need a second pipeline changing the reference value so the stencil test passes the second time. |
| if (m_params.needsStencilTest()) |
| { |
| dsStateInfo.front.reference = stencilPassVal; |
| dsStateInfo.back.reference = stencilPassVal; |
| |
| graphicsPipelines.push_back(makeGraphicsPipeline(vkd, device, pipelineLayout.get(), |
| vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(), // Shader modules. |
| renderPass.get(), 0u /*subpass*/, |
| &vertexInputInfo, &inputAssemblyInfo, nullptr, &viewportInfo, &rasterizationInfo, &multisampleInfo, &dsStateInfo, &colorBlendInfo, nullptr)); |
| } |
| } |
| |
| // Command pool and buffer. |
| const auto cmdPool = makeCommandPool(vkd, device, qIndex); |
| const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| const auto cmdBuffer = cmdBufferPtr.get(); |
| const auto renderArea = makeRect2D(extent); |
| |
| // Output buffers to check the color attachment, depth/stencil attachment and output storage images. |
| using BufferPtr = de::MovePtr<BufferWithMemory>; |
| |
| BufferPtr colorVerifBuffer; |
| BufferPtr depthVerifBuffer; |
| BufferPtr stencilVerifBuffer; |
| std::vector<BufferPtr> storageVerifBuffers; |
| |
| { |
| const auto colorVerifBufferSize = getCopyBufferSize(tcuColorFormat, extent); |
| const auto colorVerifBufferInfo = makeBufferCreateInfo(colorVerifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| colorVerifBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, colorVerifBufferInfo, MemoryRequirement::HostVisible)); |
| } |
| |
| if (hasDepth) |
| { |
| const auto depthVerifBufferSize = getCopyBufferSize(tcuDepthFormat, extent); |
| const auto depthVerifBufferInfo = makeBufferCreateInfo(depthVerifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| depthVerifBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, depthVerifBufferInfo, MemoryRequirement::HostVisible)); |
| } |
| |
| if (hasStencil) |
| { |
| const auto stencilVerifBufferSize = getCopyBufferSize(tcuStencilFormat, extent); |
| const auto stencilVerifBufferInfo = makeBufferCreateInfo(stencilVerifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| stencilVerifBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, stencilVerifBufferInfo, MemoryRequirement::HostVisible)); |
| } |
| |
| storageVerifBuffers.reserve(descriptors.size()); |
| for (const auto& desc : descriptors) |
| { |
| const auto storageFormat = getAspectStorageFormat(desc.aspect); |
| const auto tcuStorageFormat = mapVkFormat(storageFormat); |
| const auto descVerifBufferSize = getCopyBufferSize(tcuStorageFormat, extent); |
| const auto descVerifBufferInfo = makeBufferCreateInfo(descVerifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| storageVerifBuffers.emplace_back(new BufferWithMemory(vkd, device, alloc, descVerifBufferInfo, MemoryRequirement::HostVisible)); |
| } |
| |
| beginCommandBuffer(vkd, cmdBuffer); |
| |
| // Transition layout for output images. |
| std::vector<VkImageMemoryBarrier> outputImgBarriers; |
| for (const auto& outputImg : outputImages) |
| outputImgBarriers.push_back(makeImageMemoryBarrier(0u, (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, outputImg->get(), colorSRR)); |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, static_cast<uint32_t>(outputImgBarriers.size()), de::dataOrNull(outputImgBarriers)); |
| |
| // Clear color and depth/stencil buffer. |
| const auto colorPreTransferBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, colorBuffer.get(), colorSRR); |
| const auto dsPreTransferBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dsImage.get(), depthStencilSRR); |
| const std::vector<VkImageMemoryBarrier> preTransferBarriers = { colorPreTransferBarrier, dsPreTransferBarrier }; |
| |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, |
| static_cast<uint32_t>(preTransferBarriers.size()), de::dataOrNull(preTransferBarriers)); |
| |
| const auto colorClearValue = makeClearValueColorVec4(colorClearVal); |
| const auto dsClearValue = makeClearValueDepthStencil(depthClearValue, stencilClearVal); |
| |
| vkd.cmdClearColorImage(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colorClearValue.color, 1u, &colorSRR); |
| vkd.cmdClearDepthStencilImage(cmdBuffer, dsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &dsClearValue.depthStencil, 1u, &depthStencilSRR); |
| |
| const auto colorPostTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, 0u, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, colorLayout, colorBuffer.get(), colorSRR); |
| const auto dsPostTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, 0u, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_params.layout, dsImage.get(), depthStencilSRR); |
| const std::vector<VkImageMemoryBarrier> postTransferBarriers = { colorPostTransferBarrier, dsPostTransferBarrier }; |
| |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0u, 0u, nullptr, 0u, nullptr, |
| static_cast<uint32_t>(postTransferBarriers.size()), de::dataOrNull(postTransferBarriers)); |
| |
| // Render pass. |
| beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea); |
| |
| vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), |
| 0u, static_cast<uint32_t>(descriptorSets.size()), de::dataOrNull(descriptorSets), 0u, nullptr); |
| |
| const auto useSecondDraw = m_params.depthBufferNeeded(); |
| |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelines.at(0).get()); |
| { |
| if (useSecondDraw) |
| { |
| // Two draws: the first draw will use the red color. |
| pcData = PushConstantData(colorFailVal, (m_params.needsDepthTest() ? depthFailValue : depthPassValue)); |
| } |
| else |
| { |
| // If there will be no more draws, the first one needs to pass and use the right color. |
| pcData = PushConstantData(colorPassVal, depthPassValue); |
| } |
| |
| vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pcStages, 0u, pcSize, &pcData); |
| vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u); |
| } |
| if (useSecondDraw) |
| { |
| // The second draw, if used, always needs to pass and use the right color. |
| if (m_params.needsStencilTest()) |
| { |
| // Pipeline with a good stencil reference value. |
| DE_ASSERT(graphicsPipelines.size() > 1); |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelines.at(1).get()); |
| } |
| pcData = PushConstantData(colorPassVal, depthPassValue); |
| |
| vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pcStages, 0u, pcSize, &pcData); |
| vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u); |
| } |
| |
| endRenderPass(vkd, cmdBuffer); |
| |
| // Copy color attachment. |
| { |
| const auto colorLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); |
| const auto copyRegion = makeBufferImageCopy(extent, colorLayers); |
| const auto colorPostWriteBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, colorLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), colorSRR); |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorPostWriteBarrier); |
| vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorVerifBuffer->get(), 1u, ©Region); |
| } |
| |
| // Copy aspects of DS attachment. |
| { |
| const auto dsPostWriteBarrier = makeImageMemoryBarrier(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_params.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dsImage.get(), depthStencilSRR); |
| const auto fragmentTestStages = (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); |
| vkd.cmdPipelineBarrier(cmdBuffer, fragmentTestStages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &dsPostWriteBarrier); |
| |
| if (hasDepth) |
| { |
| const auto depthLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u); |
| const auto copyRegion = makeBufferImageCopy(extent, depthLayers); |
| vkd.cmdCopyImageToBuffer(cmdBuffer, dsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depthVerifBuffer->get(), 1u, ©Region); |
| } |
| |
| if (hasStencil) |
| { |
| const auto stencilLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, 1u); |
| const auto copyRegion = makeBufferImageCopy(extent, stencilLayers); |
| vkd.cmdCopyImageToBuffer(cmdBuffer, dsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stencilVerifBuffer->get(), 1u, ©Region); |
| } |
| } |
| |
| // Copy storage images. |
| { |
| std::vector<VkImageMemoryBarrier> storagePostBarriers; |
| storagePostBarriers.reserve(outputImages.size()); |
| |
| for (const auto& outImg : outputImages) |
| storagePostBarriers.push_back(makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outImg->get(), colorSRR)); |
| |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, static_cast<uint32_t>(storagePostBarriers.size()), de::dataOrNull(storagePostBarriers)); |
| |
| const auto colorLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); |
| const auto copyRegion = makeBufferImageCopy(extent, colorLayers); |
| |
| DE_ASSERT(outputImages.size() == storageVerifBuffers.size()); |
| for (size_t i = 0u; i < outputImages.size(); ++i) |
| vkd.cmdCopyImageToBuffer(cmdBuffer, outputImages[i]->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, storageVerifBuffers[i]->get(), 1u, ©Region); |
| } |
| |
| // Transfer to host barrier for buffers. |
| const auto transferToHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &transferToHostBarrier, 0u, nullptr, 0u, nullptr); |
| |
| endCommandBuffer(vkd, cmdBuffer); |
| submitCommandsAndWait(vkd, device, queue, cmdBuffer); |
| |
| // Verify the different buffers. |
| const tcu::IVec3 iExtent (static_cast<int>(extent.width), static_cast<int>(extent.height), static_cast<int>(extent.depth)); |
| auto& log = m_context.getTestContext().getLog(); |
| |
| // Verify color buffer contents. |
| { |
| auto& verifAlloc = colorVerifBuffer->getAllocation(); |
| invalidateAlloc(vkd, device, verifAlloc); |
| |
| tcu::ConstPixelBufferAccess colorPixels(tcuColorFormat, iExtent, verifAlloc.getHostPtr()); |
| if (!tcu::floatThresholdCompare(log, "ColorResult", "", colorPassVal, colorPixels, tcu::Vec4(0.0f), tcu::COMPARE_LOG_ON_ERROR)) |
| TCU_FAIL("Unexpected color buffer contents; check log for details"); |
| } |
| |
| // Verify depth buffer contents. |
| if (hasDepth) |
| { |
| auto& verifAlloc = depthVerifBuffer->getAllocation(); |
| invalidateAlloc(vkd, device, verifAlloc); |
| |
| tcu::TextureLevel referenceDepth (tcuDepthFormat, iExtent.x(), iExtent.y(), iExtent.z()); |
| auto referenceAccess = referenceDepth.getAccess(); |
| const auto refDepthVal = (depthWrites ? depthPassValue : depthClearValue); |
| |
| for (int z = 0; z < iExtent.z(); ++z) |
| for (int y = 0; y < iExtent.y(); ++y) |
| for (int x = 0; x < iExtent.x(); ++x) |
| referenceAccess.setPixDepth(refDepthVal, x, y, z); |
| |
| tcu::ConstPixelBufferAccess depthPixels(tcuDepthFormat, iExtent, verifAlloc.getHostPtr()); |
| if (!tcu::dsThresholdCompare(log, "DepthResult", "", referenceAccess, depthPixels, 0.1f, tcu::COMPARE_LOG_ON_ERROR)) |
| TCU_FAIL("Unexpected value in depth buffer; check log for details"); |
| } |
| |
| // Verify stencil buffer contents. |
| if (hasStencil) |
| { |
| auto& verifAlloc = stencilVerifBuffer->getAllocation(); |
| invalidateAlloc(vkd, device, verifAlloc); |
| |
| tcu::TextureLevel referenceStencil (tcuStencilFormat, iExtent.x(), iExtent.y(), iExtent.z()); |
| auto referenceAccess = referenceStencil.getAccess(); |
| const auto refStencilVal = static_cast<int>(stencilWrites ? stencilPassVal : stencilClearVal); |
| |
| for (int z = 0; z < iExtent.z(); ++z) |
| for (int y = 0; y < iExtent.y(); ++y) |
| for (int x = 0; x < iExtent.x(); ++x) |
| referenceAccess.setPixStencil(refStencilVal, x, y, z); |
| |
| tcu::ConstPixelBufferAccess stencilPixels(tcuStencilFormat, iExtent, verifAlloc.getHostPtr()); |
| if (!tcu::dsThresholdCompare(log, "StencilResult", "", referenceAccess, stencilPixels, 0.0f, tcu::COMPARE_LOG_ON_ERROR)) |
| TCU_FAIL("Unexpected value in stencil buffer; check log for details"); |
| } |
| |
| // Verify output images. |
| for (size_t bufferIdx = 0u; bufferIdx < storageVerifBuffers.size(); ++bufferIdx) |
| { |
| const auto& verifBuffer = storageVerifBuffers[bufferIdx]; |
| auto& verifAlloc = verifBuffer->getAllocation(); |
| invalidateAlloc(vkd, device, verifAlloc); |
| |
| const auto bufferFormat = getAspectStorageFormat(descriptors.at(bufferIdx).aspect); |
| const auto tcuBufferFormat = mapVkFormat(bufferFormat); |
| tcu::ConstPixelBufferAccess colorPixels (tcuBufferFormat, iExtent, verifAlloc.getHostPtr()); |
| const std::string resultName = "Storage" + de::toString(bufferIdx); |
| |
| if (descriptors.at(bufferIdx).aspect == VK_IMAGE_ASPECT_DEPTH_BIT) |
| { |
| if (!tcu::floatThresholdCompare(log, resultName.c_str(), "", tcu::Vec4(depthClearValue, 0.0f, 0.0f, 1.0f), colorPixels, tcu::Vec4(0.1f, 0.0f, 0.0f, 0.0f), tcu::COMPARE_LOG_ON_ERROR)) |
| TCU_FAIL("Unexpected value in depth storage buffer " + de::toString(bufferIdx) + "; check log for details"); |
| } |
| else if (descriptors.at(bufferIdx).aspect == VK_IMAGE_ASPECT_STENCIL_BIT) |
| { |
| tcu::TextureLevel stencilRef(tcuBufferFormat, iExtent.x(), iExtent.y(), iExtent.z()); |
| auto colorPIxels = stencilRef.getAccess(); |
| |
| for (int z = 0; z < iExtent.z(); ++z) |
| for (int y = 0; y < iExtent.y(); ++y) |
| for (int x = 0; x < iExtent.x(); ++x) |
| colorPIxels.setPixel(tcu::UVec4(stencilClearVal, 0u, 0u, 0u), x, y, z); |
| |
| if (!tcu::intThresholdCompare(log, resultName.c_str(), "", colorPIxels, colorPixels, tcu::UVec4(0u), tcu::COMPARE_LOG_ON_ERROR)) |
| TCU_FAIL("Unexpected value in stencil storage buffer " + de::toString(bufferIdx) + "; check log for details"); |
| } |
| else |
| DE_ASSERT(false); |
| } |
| |
| return tcu::TestStatus::pass("Pass"); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createImageDepthStencilDescriptorTests (tcu::TestContext& testCtx) |
| { |
| using TestCaseGroupPtr = de::MovePtr<tcu::TestCaseGroup>; |
| |
| const VkFormat kDepthStencilFormats[] = |
| { |
| VK_FORMAT_D16_UNORM, |
| VK_FORMAT_X8_D24_UNORM_PACK32, |
| VK_FORMAT_D32_SFLOAT, |
| VK_FORMAT_S8_UINT, |
| VK_FORMAT_D16_UNORM_S8_UINT, |
| VK_FORMAT_D24_UNORM_S8_UINT, |
| VK_FORMAT_D32_SFLOAT_S8_UINT, |
| }; |
| |
| // Layouts used in these tests as VkDescriptorImageInfo::imageLayout. |
| const VkImageLayout kTestedLayouts[] = |
| { |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, |
| VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, |
| }; |
| |
| // Types of read-only combinations to test. |
| ROAccessVec kReadOnlyDSAttachment = { ReadOnlyAccess::DS_ATTACHMENT }; |
| ROAccessVec kReadOnlyInputAttachment = { ReadOnlyAccess::INPUT_ATTACHMENT }; |
| ROAccessVec kReadOnlySampled = { ReadOnlyAccess::SAMPLED }; |
| ROAccessVec kReadOnlyDSSampled = { ReadOnlyAccess::DS_ATTACHMENT, ReadOnlyAccess::SAMPLED }; |
| ROAccessVec kReadOnlyInputSampled = { ReadOnlyAccess::INPUT_ATTACHMENT, ReadOnlyAccess::SAMPLED }; |
| |
| const ROAccessVec* kROAccessCases[] = |
| { |
| &kReadOnlyDSAttachment, |
| &kReadOnlyInputAttachment, |
| &kReadOnlySampled, |
| &kReadOnlyDSSampled, |
| &kReadOnlyInputSampled, |
| }; |
| |
| const auto kLayoutPrefixLen = std::string("VK_IMAGE_LAYOUT_").size(); |
| const auto kFormatPrefixLen = std::string("VK_FORMAT_").size(); |
| |
| TestCaseGroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "depth_stencil_descriptor", "Tests using depth/stencil images as descriptors")); |
| |
| for (const auto& layout : kTestedLayouts) |
| { |
| const auto layoutStr = de::toString(layout); |
| const auto layoutGroupName = de::toLower(layoutStr.substr(kLayoutPrefixLen)); |
| const auto layoutGroupDesc = "Tests using the " + layoutStr + " layout"; |
| |
| TestCaseGroupPtr layoutGroup(new tcu::TestCaseGroup(testCtx, layoutGroupName.c_str(), layoutGroupDesc.c_str())); |
| |
| for (const auto& format : kDepthStencilFormats) |
| { |
| const auto formatStr = de::toString(format); |
| const auto formatGroupName = de::toLower(formatStr.substr(kFormatPrefixLen)); |
| const auto formatGroupDesc = "Tests using the " + formatStr + " format"; |
| |
| TestCaseGroupPtr formatGroup(new tcu::TestCaseGroup(testCtx, formatGroupName.c_str(), formatGroupDesc.c_str())); |
| |
| const auto depthAccess = getLegalAccess(layout, VK_IMAGE_ASPECT_DEPTH_BIT); |
| const auto stencilAccess = getLegalAccess(layout, VK_IMAGE_ASPECT_STENCIL_BIT); |
| const auto tcuFormat = mapVkFormat(format); |
| |
| const auto hasDepthAccess = (depthAccess != AspectAccess::NONE); |
| const auto hasStencilAccess = (stencilAccess != AspectAccess::NONE); |
| const auto hasDepth = tcu::hasDepthComponent(tcuFormat.order); |
| const auto hasStencil = tcu::hasStencilComponent(tcuFormat.order); |
| |
| if (hasDepthAccess != hasDepth) |
| continue; |
| if (hasStencilAccess != hasStencil) |
| continue; |
| |
| if (depthAccess == AspectAccess::RO) |
| { |
| for (const auto& depthROCase : kROAccessCases) |
| { |
| const std::string depthPart = "depth_" + de::toString(*depthROCase); |
| if (stencilAccess == AspectAccess::RO) |
| { |
| for (const auto& stencilROCase : kROAccessCases) |
| { |
| if (incompatibleInputAttachmentAccess(depthAccess, depthROCase, stencilAccess, stencilROCase)) |
| continue; |
| |
| const std::string stencilPart = "_stencil_" + de::toString(*stencilROCase); |
| const TestParams params = |
| { |
| format, // VkFormat format; |
| layout, // VkImageLayout layout; |
| depthAccess, // AspectAccess depthAccess; |
| stencilAccess, // AspectAccess stencilAccess; |
| tcu::just(*depthROCase), // tcu::Maybe<ROAccessVec> depthROAccesses; |
| tcu::just(*stencilROCase), // tcu::Maybe<ROAccessVec> stencilROAccesses; |
| }; |
| formatGroup->addChild(new DepthStencilDescriptorCase(testCtx, depthPart + stencilPart, "", params)); |
| } |
| } |
| else |
| { |
| if (incompatibleInputAttachmentAccess(depthAccess, depthROCase, stencilAccess, nullptr)) |
| continue; |
| |
| const std::string stencilPart = "_stencil_" + de::toString(stencilAccess); |
| const TestParams params = |
| { |
| format, // VkFormat format; |
| layout, // VkImageLayout layout; |
| depthAccess, // AspectAccess depthAccess; |
| stencilAccess, // AspectAccess stencilAccess; |
| tcu::just(*depthROCase), // tcu::Maybe<ROAccessVec> depthROAccesses; |
| tcu::Nothing, // tcu::Maybe<ROAccessVec> stencilROAccesses; |
| }; |
| formatGroup->addChild(new DepthStencilDescriptorCase(testCtx, depthPart + stencilPart, "", params)); |
| } |
| } |
| } |
| else |
| { |
| const std::string depthPart = "depth_" + de::toString(depthAccess); |
| |
| if (stencilAccess == AspectAccess::RO) |
| { |
| for (const auto& stencilROCase : kROAccessCases) |
| { |
| if (incompatibleInputAttachmentAccess(depthAccess, nullptr, stencilAccess, stencilROCase)) |
| continue; |
| |
| const std::string stencilPart = "_stencil_" + de::toString(*stencilROCase); |
| const TestParams params = |
| { |
| format, // VkFormat format; |
| layout, // VkImageLayout layout; |
| depthAccess, // AspectAccess depthAccess; |
| stencilAccess, // AspectAccess stencilAccess; |
| tcu::Nothing, // tcu::Maybe<ROAccessVec> depthROAccesses; |
| tcu::just(*stencilROCase), // tcu::Maybe<ROAccessVec> stencilROAccesses; |
| }; |
| formatGroup->addChild(new DepthStencilDescriptorCase(testCtx, depthPart + stencilPart, "", params)); |
| } |
| } |
| else |
| { |
| if (incompatibleInputAttachmentAccess(depthAccess, nullptr, stencilAccess, nullptr)) |
| continue; |
| |
| const std::string stencilPart = "_stencil_" + de::toString(stencilAccess); |
| const TestParams params = |
| { |
| format, // VkFormat format; |
| layout, // VkImageLayout layout; |
| depthAccess, // AspectAccess depthAccess; |
| stencilAccess, // AspectAccess stencilAccess; |
| tcu::Nothing, // tcu::Maybe<ROAccessVec> depthROAccesses; |
| tcu::Nothing, // tcu::Maybe<ROAccessVec> stencilROAccesses; |
| }; |
| formatGroup->addChild(new DepthStencilDescriptorCase(testCtx, depthPart + stencilPart, "", params)); |
| } |
| } |
| |
| layoutGroup->addChild(formatGroup.release()); |
| } |
| |
| mainGroup->addChild(layoutGroup.release()); |
| } |
| |
| return mainGroup.release(); |
| } |
| |
| } // image |
| } // vkt |