| /*------------------------------------------------------------------------- |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2018 The Khronos Group Inc. |
| * |
| * 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 VK_KHR_depth_stencil_resolve tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktRenderPassDepthStencilResolveTests.hpp" |
| #include "vktRenderPassTestsUtil.hpp" |
| |
| #include "vktTestCaseUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| |
| #include "vkDefs.hpp" |
| #include "vkDeviceUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkPlatform.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkRef.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "tcuImageCompare.hpp" |
| #include "tcuFormatUtil.hpp" |
| #include "tcuResultCollector.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTextureUtil.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deSharedPtr.hpp" |
| #include "deMath.h" |
| #include <limits> |
| |
| using namespace vk; |
| |
| using tcu::Vec4; |
| using tcu::TestLog; |
| |
| typedef de::SharedPtr<vk::Unique<VkImage> > VkImageSp; |
| typedef de::SharedPtr<vk::Unique<VkImageView> > VkImageViewSp; |
| typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; |
| typedef de::SharedPtr<vk::Unique<VkPipeline> > VkPipelineSp; |
| typedef de::SharedPtr<Allocation> AllocationSp; |
| |
| namespace vkt |
| { |
| namespace |
| { |
| |
| using namespace renderpass; |
| |
| template<typename T> |
| de::SharedPtr<T> safeSharedPtr (T* ptr) |
| { |
| try |
| { |
| return de::SharedPtr<T>(ptr); |
| } |
| catch (...) |
| { |
| delete ptr; |
| throw; |
| } |
| } |
| |
| enum VerifyBuffer |
| { |
| VB_DEPTH = 0, |
| VB_STENCIL |
| }; |
| |
| struct TestConfig |
| { |
| VkFormat format; |
| deUint32 width; |
| deUint32 height; |
| deUint32 imageLayers; |
| deUint32 viewLayers; |
| deUint32 resolveBaseLayer; |
| VkRect2D renderArea; |
| VkImageAspectFlags aspectFlag; |
| deUint32 sampleCount; |
| VkResolveModeFlagBitsKHR depthResolveMode; |
| VkResolveModeFlagBitsKHR stencilResolveMode; |
| VerifyBuffer verifyBuffer; |
| VkClearDepthStencilValue clearValue; |
| float depthExpectedValue; |
| deUint8 stencilExpectedValue; |
| }; |
| |
| float get16bitDepthComponent(deUint8* pixelPtr) |
| { |
| deUint16* value = reinterpret_cast<deUint16*>(pixelPtr); |
| return static_cast<float>(*value) / 65535.0f; |
| } |
| |
| float get24bitDepthComponent(deUint8* pixelPtr) |
| { |
| const bool littleEndian = (DE_ENDIANNESS == DE_LITTLE_ENDIAN); |
| deUint32 value = (((deUint32)pixelPtr[0]) << (!littleEndian * 16u)) | |
| (((deUint32)pixelPtr[1]) << 8u) | |
| (((deUint32)pixelPtr[2]) << ( littleEndian * 16u)); |
| return static_cast<float>(value) / 16777215.0f; |
| } |
| |
| float get32bitDepthComponent(deUint8* pixelPtr) |
| { |
| return *(reinterpret_cast<float*>(pixelPtr)); |
| } |
| |
| class DepthStencilResolveTest : public TestInstance |
| { |
| public: |
| DepthStencilResolveTest (Context& context, TestConfig config); |
| virtual ~DepthStencilResolveTest (void); |
| |
| virtual tcu::TestStatus iterate (void); |
| |
| protected: |
| bool isFeaturesSupported (void); |
| VkSampleCountFlagBits sampleCountBitFromSampleCount (deUint32 count) const; |
| |
| VkImageSp createImage (deUint32 sampleCount, VkImageUsageFlags additionalUsage = 0u); |
| AllocationSp createImageMemory (VkImageSp image); |
| VkImageViewSp createImageView (VkImageSp image, deUint32 baseArrayLayer); |
| AllocationSp createBufferMemory (void); |
| VkBufferSp createBuffer (void); |
| |
| Move<VkRenderPass> createRenderPass (void); |
| Move<VkFramebuffer> createFramebuffer (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView); |
| Move<VkPipelineLayout> createRenderPipelineLayout (void); |
| Move<VkPipeline> createRenderPipeline (VkRenderPass renderPass, VkPipelineLayout renderPipelineLayout); |
| |
| void submit (void); |
| bool verifyDepth (void); |
| bool verifyStencil (void); |
| |
| protected: |
| const TestConfig m_config; |
| const bool m_featureSupported; |
| |
| const InstanceInterface& m_vki; |
| const DeviceInterface& m_vkd; |
| VkDevice m_device; |
| VkPhysicalDevice m_physicalDevice; |
| |
| VkImageSp m_multisampleImage; |
| AllocationSp m_multisampleImageMemory; |
| VkImageViewSp m_multisampleImageView; |
| VkImageSp m_singlesampleImage; |
| AllocationSp m_singlesampleImageMemory; |
| VkImageViewSp m_singlesampleImageView; |
| VkBufferSp m_buffer; |
| AllocationSp m_bufferMemory; |
| |
| Unique<VkRenderPass> m_renderPass; |
| Unique<VkFramebuffer> m_framebuffer; |
| Unique<VkPipelineLayout> m_renderPipelineLayout; |
| Unique<VkPipeline> m_renderPipeline; |
| |
| const Unique<VkCommandPool> m_commandPool; |
| }; |
| |
| DepthStencilResolveTest::DepthStencilResolveTest (Context& context, TestConfig config) |
| : TestInstance (context) |
| , m_config (config) |
| , m_featureSupported (isFeaturesSupported()) |
| , m_vki (context.getInstanceInterface()) |
| , m_vkd (context.getDeviceInterface()) |
| , m_device (context.getDevice()) |
| , m_physicalDevice (context.getPhysicalDevice()) |
| |
| , m_multisampleImage (createImage(m_config.sampleCount)) |
| , m_multisampleImageMemory (createImageMemory(m_multisampleImage)) |
| , m_multisampleImageView (createImageView(m_multisampleImage, 0u)) |
| |
| , m_singlesampleImage (createImage(1, VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) |
| , m_singlesampleImageMemory (createImageMemory(m_singlesampleImage)) |
| , m_singlesampleImageView (createImageView(m_singlesampleImage, m_config.resolveBaseLayer)) |
| |
| , m_buffer (createBuffer()) |
| , m_bufferMemory (createBufferMemory()) |
| |
| , m_renderPass (createRenderPass()) |
| , m_framebuffer (createFramebuffer(*m_renderPass, m_multisampleImageView, m_singlesampleImageView)) |
| , m_renderPipelineLayout (createRenderPipelineLayout()) |
| , m_renderPipeline (createRenderPipeline(*m_renderPass, *m_renderPipelineLayout)) |
| |
| |
| , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) |
| { |
| } |
| |
| DepthStencilResolveTest::~DepthStencilResolveTest (void) |
| { |
| } |
| |
| bool DepthStencilResolveTest::isFeaturesSupported() |
| { |
| m_context.requireDeviceExtension("VK_KHR_depth_stencil_resolve"); |
| if (m_config.imageLayers > 1) |
| m_context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); |
| |
| VkPhysicalDeviceDepthStencilResolvePropertiesKHR dsResolveProperties; |
| deMemset(&dsResolveProperties, 0, sizeof(VkPhysicalDeviceDepthStencilResolvePropertiesKHR)); |
| dsResolveProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; |
| dsResolveProperties.pNext = DE_NULL; |
| |
| VkPhysicalDeviceProperties2 deviceProperties; |
| deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; |
| deviceProperties.pNext = &dsResolveProperties; |
| |
| // perform query to get supported float control properties |
| const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| const vk::InstanceInterface& instanceInterface = m_context.getInstanceInterface(); |
| instanceInterface.getPhysicalDeviceProperties2(physicalDevice, &deviceProperties); |
| |
| // check if both modes are supported |
| VkResolveModeFlagBitsKHR depthResolveMode = m_config.depthResolveMode; |
| VkResolveModeFlagBitsKHR stencilResolveMode = m_config.stencilResolveMode; |
| if ((depthResolveMode != VK_RESOLVE_MODE_NONE_KHR) && |
| !(depthResolveMode & dsResolveProperties.supportedDepthResolveModes)) |
| TCU_THROW(NotSupportedError, "Depth resolve mode not supported"); |
| if ((stencilResolveMode != VK_RESOLVE_MODE_NONE_KHR) && |
| !(stencilResolveMode & dsResolveProperties.supportedStencilResolveModes)) |
| TCU_THROW(NotSupportedError, "Stencil resolve mode not supported"); |
| |
| // check if the implementation supports setting the depth and stencil resolve |
| // modes to different values when one of those modes is VK_RESOLVE_MODE_NONE_KHR |
| if (dsResolveProperties.independentResolveNone) |
| { |
| if ((!dsResolveProperties.independentResolve) && |
| (depthResolveMode != stencilResolveMode) && |
| (depthResolveMode != VK_RESOLVE_MODE_NONE_KHR) && |
| (stencilResolveMode != VK_RESOLVE_MODE_NONE_KHR)) |
| TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes"); |
| } |
| else if (depthResolveMode != stencilResolveMode) |
| { |
| // when independentResolveNone is VK_FALSE then both modes must be the same |
| TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes"); |
| } |
| |
| // check if the implementation supports all combinations of the supported depth and stencil resolve modes |
| if (!dsResolveProperties.independentResolve && (depthResolveMode != stencilResolveMode)) |
| TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes"); |
| |
| return true; |
| } |
| |
| VkSampleCountFlagBits DepthStencilResolveTest::sampleCountBitFromSampleCount (deUint32 count) const |
| { |
| switch (count) |
| { |
| case 1: return VK_SAMPLE_COUNT_1_BIT; |
| case 2: return VK_SAMPLE_COUNT_2_BIT; |
| case 4: return VK_SAMPLE_COUNT_4_BIT; |
| case 8: return VK_SAMPLE_COUNT_8_BIT; |
| case 16: return VK_SAMPLE_COUNT_16_BIT; |
| case 32: return VK_SAMPLE_COUNT_32_BIT; |
| case 64: return VK_SAMPLE_COUNT_64_BIT; |
| |
| default: |
| DE_FATAL("Invalid sample count"); |
| return (VkSampleCountFlagBits)0x0; |
| } |
| } |
| |
| VkImageSp DepthStencilResolveTest::createImage (deUint32 sampleCount, VkImageUsageFlags additionalUsage) |
| { |
| const tcu::TextureFormat format(mapVkFormat(m_config.format)); |
| const VkImageTiling imageTiling(VK_IMAGE_TILING_OPTIMAL); |
| VkSampleCountFlagBits sampleCountBit(sampleCountBitFromSampleCount(sampleCount)); |
| VkImageUsageFlags usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | additionalUsage; |
| |
| VkImageFormatProperties imageFormatProperties; |
| if (m_vki.getPhysicalDeviceImageFormatProperties(m_physicalDevice, m_config.format, VK_IMAGE_TYPE_2D, imageTiling, |
| usage, 0u, &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| { |
| TCU_THROW(NotSupportedError, "Format not supported"); |
| } |
| if (imageFormatProperties.sampleCounts < sampleCount) |
| { |
| TCU_THROW(NotSupportedError, "Sample count not supported"); |
| } |
| if (imageFormatProperties.maxArrayLayers < m_config.imageLayers) |
| { |
| TCU_THROW(NotSupportedError, "Layers count not supported"); |
| } |
| |
| const VkExtent3D imageExtent = |
| { |
| m_config.width, |
| m_config.height, |
| 1u |
| }; |
| |
| if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))) |
| TCU_THROW(NotSupportedError, "Format can't be used as depth/stencil attachment"); |
| |
| if (imageFormatProperties.maxExtent.width < imageExtent.width |
| || imageFormatProperties.maxExtent.height < imageExtent.height |
| || ((imageFormatProperties.sampleCounts & sampleCountBit) == 0) |
| || imageFormatProperties.maxArrayLayers < m_config.imageLayers) |
| { |
| TCU_THROW(NotSupportedError, "Image type not supported"); |
| } |
| |
| const VkImageCreateInfo pCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| VK_IMAGE_TYPE_2D, |
| m_config.format, |
| imageExtent, |
| 1u, |
| m_config.imageLayers, |
| sampleCountBit, |
| imageTiling, |
| usage, |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0u, |
| DE_NULL, |
| VK_IMAGE_LAYOUT_UNDEFINED |
| }; |
| |
| return safeSharedPtr(new Unique<VkImage>(vk::createImage(m_vkd, m_device, &pCreateInfo))); |
| } |
| |
| AllocationSp DepthStencilResolveTest::createImageMemory (VkImageSp image) |
| { |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| |
| de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(m_vkd, m_device, **image), MemoryRequirement::Any)); |
| VK_CHECK(m_vkd.bindImageMemory(m_device, **image, allocation->getMemory(), allocation->getOffset())); |
| return safeSharedPtr(allocation.release()); |
| } |
| |
| VkImageViewSp DepthStencilResolveTest::createImageView (VkImageSp image, deUint32 baseArrayLayer) |
| { |
| const VkImageSubresourceRange range = |
| { |
| m_config.aspectFlag, |
| 0u, |
| 1u, |
| baseArrayLayer, |
| m_config.viewLayers |
| }; |
| |
| const VkImageViewCreateInfo pCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| **image, |
| (m_config.viewLayers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, |
| m_config.format, |
| makeComponentMappingRGBA(), |
| range, |
| }; |
| return safeSharedPtr(new Unique<VkImageView>(vk::createImageView(m_vkd, m_device, &pCreateInfo))); |
| } |
| |
| Move<VkRenderPass> DepthStencilResolveTest::createRenderPass (void) |
| { |
| const VkSampleCountFlagBits samples(sampleCountBitFromSampleCount(m_config.sampleCount)); |
| |
| const AttachmentDescription2 multisampleAttachment // VkAttachmentDescription2KHR |
| ( |
| // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkAttachmentDescriptionFlags flags; |
| m_config.format, // VkFormat format; |
| samples, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; |
| ); |
| const AttachmentReference2 multisampleAttachmentRef // VkAttachmentReference2KHR |
| ( |
| // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // deUint32 attachment; |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout; |
| 0u // VkImageAspectFlags aspectMask; |
| ); |
| |
| const AttachmentDescription2 singlesampleAttachment // VkAttachmentDescription2KHR |
| ( |
| // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkAttachmentDescriptionFlags flags; |
| m_config.format, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; |
| ); |
| AttachmentReference2 singlesampleAttachmentRef // VkAttachmentReference2KHR |
| ( |
| // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 1u, // deUint32 attachment; |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout; |
| 0u // VkImageAspectFlags aspectMask; |
| ); |
| |
| std::vector<AttachmentDescription2> attachments; |
| attachments.push_back(multisampleAttachment); |
| attachments.push_back(singlesampleAttachment); |
| |
| VkSubpassDescriptionDepthStencilResolveKHR dsResolveDescription = |
| { |
| VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR, |
| DE_NULL, // const void* pNext; |
| m_config.depthResolveMode, // VkResolveModeFlagBitsKHR depthResolveMode; |
| m_config.stencilResolveMode, // VkResolveModeFlagBitsKHR stencilResolveMode; |
| &singlesampleAttachmentRef // VkAttachmentReference2KHR pDepthStencilResolveAttachment; |
| }; |
| |
| const SubpassDescription2 subpass // VkSubpassDescription2KHR |
| ( |
| // VkStructureType sType; |
| &dsResolveDescription, // const void* pNext; |
| (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; |
| 0u, // deUint32 viewMask; |
| 0u, // deUint32 inputAttachmentCount; |
| DE_NULL, // const VkAttachmentReference2KHR* pInputAttachments; |
| 0u, // deUint32 colorAttachmentCount; |
| DE_NULL, // const VkAttachmentReference2KHR* pColorAttachments; |
| DE_NULL, // const VkAttachmentReference2KHR* pResolveAttachments; |
| &multisampleAttachmentRef, // const VkAttachmentReference2KHR* pDepthStencilAttachment; |
| 0u, // deUint32 preserveAttachmentCount; |
| DE_NULL // const deUint32* pPreserveAttachments; |
| ); |
| |
| const RenderPassCreateInfo2 renderPassCreator // VkRenderPassCreateInfo2KHR |
| ( |
| // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags; |
| (deUint32)attachments.size(), // deUint32 attachmentCount; |
| &attachments[0], // const VkAttachmentDescription2KHR* pAttachments; |
| 1u, // deUint32 subpassCount; |
| &subpass, // const VkSubpassDescription2KHR* pSubpasses; |
| 0u, // deUint32 dependencyCount; |
| DE_NULL, // const VkSubpassDependency2KHR* pDependencies; |
| 0u, // deUint32 correlatedViewMaskCount; |
| DE_NULL // const deUint32* pCorrelatedViewMasks; |
| ); |
| |
| return renderPassCreator.createRenderPass(m_vkd, m_device); |
| } |
| |
| Move<VkFramebuffer> DepthStencilResolveTest::createFramebuffer (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView) |
| { |
| std::vector<VkImageView> attachments; |
| attachments.push_back(**multisampleImageView); |
| attachments.push_back(**singlesampleImageView); |
| |
| const VkFramebufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| |
| renderPass, |
| (deUint32)attachments.size(), |
| &attachments[0], |
| |
| m_config.width, |
| m_config.height, |
| m_config.viewLayers |
| }; |
| |
| return vk::createFramebuffer(m_vkd, m_device, &createInfo); |
| } |
| |
| Move<VkPipelineLayout> DepthStencilResolveTest::createRenderPipelineLayout (void) |
| { |
| VkPushConstantRange pushConstant = |
| { |
| VK_SHADER_STAGE_FRAGMENT_BIT, |
| 0u, |
| 4u |
| }; |
| |
| deUint32 pushConstantRangeCount = 0u; |
| VkPushConstantRange* pPushConstantRanges = DE_NULL; |
| if (m_config.verifyBuffer == VB_STENCIL) |
| { |
| pushConstantRangeCount = 1u; |
| pPushConstantRanges = &pushConstant; |
| } |
| |
| const VkPipelineLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| DE_NULL, |
| (vk::VkPipelineLayoutCreateFlags)0, |
| |
| 0u, |
| DE_NULL, |
| |
| pushConstantRangeCount, |
| pPushConstantRanges |
| }; |
| |
| return vk::createPipelineLayout(m_vkd, m_device, &createInfo); |
| } |
| |
| Move<VkPipeline> DepthStencilResolveTest::createRenderPipeline (VkRenderPass renderPass, VkPipelineLayout renderPipelineLayout) |
| { |
| const bool testingStencil = (m_config.verifyBuffer == VB_STENCIL); |
| const vk::BinaryCollection& binaryCollection = m_context.getBinaryCollection(); |
| |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(m_vkd, m_device, binaryCollection.get("quad-vert"), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(m_vkd, m_device, binaryCollection.get("quad-frag"), 0u)); |
| const Move<VkShaderModule> geometryShaderModule (m_config.imageLayers == 1 ? Move<VkShaderModule>() : createShaderModule(m_vkd, m_device, binaryCollection.get("quad-geom"), 0u)); |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineVertexInputStateCreateFlags)0u, |
| |
| 0u, |
| DE_NULL, |
| |
| 0u, |
| DE_NULL |
| }; |
| const tcu::UVec2 view (m_config.width, m_config.height); |
| const std::vector<VkViewport> viewports (1, makeViewport(view)); |
| const std::vector<VkRect2D> scissors (1, m_config.renderArea); |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineMultisampleStateCreateFlags)0u, |
| |
| sampleCountBitFromSampleCount(m_config.sampleCount), |
| VK_FALSE, |
| 0.0f, |
| DE_NULL, |
| VK_FALSE, |
| VK_FALSE, |
| }; |
| const VkPipelineDepthStencilStateCreateInfo depthStencilState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, |
| DE_NULL, |
| (VkPipelineDepthStencilStateCreateFlags)0u, |
| |
| VK_TRUE, // depthTestEnable |
| VK_TRUE, |
| VK_COMPARE_OP_ALWAYS, |
| VK_FALSE, |
| testingStencil, // stencilTestEnable |
| { |
| VK_STENCIL_OP_REPLACE, // failOp |
| VK_STENCIL_OP_REPLACE, // passOp |
| VK_STENCIL_OP_REPLACE, // depthFailOp |
| VK_COMPARE_OP_ALWAYS, // compareOp |
| 0xFFu, // compareMask |
| 0xFFu, // writeMask |
| 1 // reference |
| }, |
| { |
| VK_STENCIL_OP_REPLACE, |
| VK_STENCIL_OP_REPLACE, |
| VK_STENCIL_OP_REPLACE, |
| VK_COMPARE_OP_ALWAYS, |
| 0xFFu, |
| 0xFFu, |
| 1 |
| }, |
| 0.0f, |
| 1.0f |
| }; |
| |
| std::vector<VkDynamicState> dynamicState; |
| dynamicState.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); |
| const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineDynamicStateCreateFlags)0u, // VkPipelineDynamicStateCreateFlags flags; |
| static_cast<deUint32>(dynamicState.size()), // deUint32 dynamicStateCount; |
| &dynamicState[0] // const VkDynamicState* pDynamicStates; |
| }; |
| |
| return makeGraphicsPipeline(m_vkd, // const DeviceInterface& vk |
| m_device, // const VkDevice device |
| renderPipelineLayout, // const VkPipelineLayout pipelineLayout |
| *vertexShaderModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlShaderModule |
| DE_NULL, // const VkShaderModule tessellationEvalShaderModule |
| m_config.imageLayers == 1 ? DE_NULL : *geometryShaderModule, // const VkShaderModule geometryShaderModule |
| *fragmentShaderModule, // const VkShaderModule fragmentShaderModule |
| renderPass, // const VkRenderPass renderPass |
| viewports, // const std::vector<VkViewport>& viewports |
| scissors, // const std::vector<VkRect2D>& scissors |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology |
| 0u, // const deUint32 subpass |
| 0u, // const deUint32 patchControlPoints |
| &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo |
| &multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo |
| &depthStencilState, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo |
| DE_NULL, // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo |
| testingStencil ? &dynamicStateCreateInfo : DE_NULL); // const VkPipelineDynamicStateCreateInfo* dynamicStateCreateInfo |
| } |
| |
| AllocationSp DepthStencilResolveTest::createBufferMemory (void) |
| { |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| de::MovePtr<Allocation> allocation(allocator.allocate(getBufferMemoryRequirements(m_vkd, m_device, **m_buffer), MemoryRequirement::HostVisible)); |
| VK_CHECK(m_vkd.bindBufferMemory(m_device, **m_buffer, allocation->getMemory(), allocation->getOffset())); |
| return safeSharedPtr(allocation.release()); |
| } |
| |
| VkBufferSp DepthStencilResolveTest::createBuffer (void) |
| { |
| const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const tcu::TextureFormat textureFormat (mapVkFormat(m_config.format)); |
| const VkDeviceSize pixelSize (textureFormat.getPixelSize()); |
| const VkBufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| DE_NULL, |
| 0u, |
| |
| m_config.width * m_config.height * m_config.imageLayers * pixelSize, |
| bufferUsage, |
| |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0u, |
| DE_NULL |
| }; |
| return safeSharedPtr(new Unique<VkBuffer>(vk::createBuffer(m_vkd, m_device, &createInfo))); |
| } |
| |
| void DepthStencilResolveTest::submit (void) |
| { |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const VkDevice device (m_context.getDevice()); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const RenderpassSubpass2::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const RenderpassSubpass2::SubpassEndInfo subpassEndInfo (DE_NULL); |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| |
| { |
| VkClearValue clearValues[2]; |
| clearValues[0].depthStencil = m_config.clearValue; |
| clearValues[1].depthStencil = m_config.clearValue; |
| |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| DE_NULL, |
| |
| *m_renderPass, |
| *m_framebuffer, |
| |
| { |
| { 0u, 0u }, |
| { m_config.width, m_config.height } |
| }, |
| |
| 2u, |
| clearValues |
| }; |
| RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| // Render |
| bool testingDepth = (m_config.verifyBuffer == VB_DEPTH); |
| if (testingDepth) |
| { |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline); |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| else |
| { |
| // For stencil we can set reference value for just one sample at a time |
| // so we need to do as many passes as there are samples, first half |
| // of samples is initialized with 1 and second half with 255 |
| const deUint32 halfOfSamples = m_config.sampleCount >> 1; |
| for (deUint32 renderPass = 0 ; renderPass < m_config.sampleCount ; renderPass++) |
| { |
| deUint32 stencilReference = 1 + 254 * (renderPass >= halfOfSamples); |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline); |
| vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(renderPass), &renderPass); |
| vkd.cmdSetStencilReference(*commandBuffer, VK_STENCIL_FRONT_AND_BACK, stencilReference); |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| } |
| |
| RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| |
| // Memory barriers between rendering and copying |
| { |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT, |
| |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_singlesampleImage, |
| { |
| m_config.aspectFlag, |
| 0u, |
| 1u, |
| 0u, |
| m_config.viewLayers |
| } |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); |
| } |
| |
| // Copy image memory to buffers |
| const VkBufferImageCopy region = |
| { |
| 0u, |
| 0u, |
| 0u, |
| { |
| testingDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT, |
| 0u, |
| 0u, |
| m_config.viewLayers, |
| }, |
| { 0u, 0u, 0u }, |
| { m_config.width, m_config.height, 1u } |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_singlesampleImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_buffer, 1u, ®ion); |
| |
| // Memory barriers between copies and host access |
| { |
| const VkBufferMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| DE_NULL, |
| |
| VK_ACCESS_TRANSFER_WRITE_BIT, |
| VK_ACCESS_HOST_READ_BIT, |
| |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| |
| **m_buffer, |
| 0u, |
| VK_WHOLE_SIZE |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL); |
| } |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| |
| submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer); |
| } |
| |
| bool DepthStencilResolveTest::verifyDepth (void) |
| { |
| deUint32 layerSize = m_config.width * m_config.height; |
| deUint32 valuesCount = layerSize * m_config.viewLayers; |
| deUint8* pixelPtr = static_cast<deUint8*>(m_bufferMemory->getHostPtr()); |
| |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), m_bufferMemory->getMemory(), m_bufferMemory->getOffset(), VK_WHOLE_SIZE); |
| |
| float expectedValue = m_config.depthExpectedValue; |
| if (m_config.depthResolveMode == VK_RESOLVE_MODE_NONE_KHR) |
| expectedValue = m_config.clearValue.depth; |
| |
| // depth data in buffer is tightly packed, ConstPixelBufferAccess |
| // coludn't be used for depth value extraction as it cant interpret |
| // formats containing just depth component |
| |
| typedef float (*DepthComponentGetterFn)(deUint8*); |
| VkFormat format = m_config.format; |
| DepthComponentGetterFn getDepthComponent = &get16bitDepthComponent; |
| deUint32 pixelStep = 2; |
| float epsilon = 0.002f; |
| |
| if ((format == VK_FORMAT_X8_D24_UNORM_PACK32) || |
| (format == VK_FORMAT_D24_UNORM_S8_UINT)) |
| { |
| getDepthComponent = &get24bitDepthComponent; |
| pixelStep = 4; |
| } |
| else if ((format == VK_FORMAT_D32_SFLOAT) || |
| (format == VK_FORMAT_D32_SFLOAT_S8_UINT)) |
| { |
| getDepthComponent = &get32bitDepthComponent; |
| pixelStep = 4; |
| } |
| |
| for (deUint32 valueIndex = 0; valueIndex < valuesCount; valueIndex++) |
| { |
| float depth = (*getDepthComponent)(pixelPtr); |
| pixelPtr += pixelStep; |
| |
| // check if pixel data is outside of render area |
| deInt32 layerIndex = valueIndex / layerSize; |
| deInt32 inLayerIndex = valueIndex % layerSize; |
| deInt32 x = inLayerIndex % m_config.width; |
| deInt32 y = (inLayerIndex - x) / m_config.width; |
| deInt32 x1 = m_config.renderArea.offset.x; |
| deInt32 y1 = m_config.renderArea.offset.y; |
| deInt32 x2 = x1 + m_config.renderArea.extent.width; |
| deInt32 y2 = y1 + m_config.renderArea.extent.height; |
| if ((x < x1) || (x >= x2) || (y < y1) || (y >= y2)) |
| { |
| // verify that outside of render area there are clear values |
| float error = deFloatAbs(depth - m_config.clearValue.depth); |
| if (error > epsilon) |
| { |
| m_context.getTestContext().getLog() |
| << TestLog::Message << "(" << x << ", " << y |
| << ", layer: " << layerIndex << ") is outside of render area but depth value is: " |
| << depth << " (expected " << m_config.clearValue.depth << ")" << TestLog::EndMessage; |
| return false; |
| } |
| |
| // value is correct, go to next one |
| continue; |
| } |
| |
| float error = deFloatAbs(depth - expectedValue); |
| if (error > epsilon) |
| { |
| m_context.getTestContext().getLog() << TestLog::Message |
| << "At (" << x << ", " << y << ", layer: " << layerIndex |
| << ") depth value is: " << depth << " expected: " |
| << expectedValue << TestLog::EndMessage; |
| return false; |
| } |
| } |
| m_context.getTestContext().getLog() << TestLog::Message |
| << "Depth value is " << expectedValue |
| << TestLog::EndMessage; |
| |
| return true; |
| } |
| |
| bool DepthStencilResolveTest::verifyStencil (void) |
| { |
| deUint32 layerSize = m_config.width * m_config.height; |
| deUint32 valuesCount = layerSize * m_config.viewLayers; |
| deUint8* pixelPtr = static_cast<deUint8*>(m_bufferMemory->getHostPtr()); |
| |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), m_bufferMemory->getMemory(), m_bufferMemory->getOffset(), VK_WHOLE_SIZE); |
| |
| // when stencil is tested we are discarding invocations and |
| // because of that depth and stencil need to be tested separately |
| |
| deUint8 expectedValue = m_config.stencilExpectedValue; |
| if (m_config.stencilResolveMode == VK_RESOLVE_MODE_NONE_KHR) |
| expectedValue = static_cast<deUint8>(m_config.clearValue.stencil); |
| |
| for (deUint32 valueIndex = 0; valueIndex < valuesCount; valueIndex++) |
| { |
| deUint8 stencil = *pixelPtr++; |
| deInt32 layerIndex = valueIndex / layerSize; |
| deInt32 inLayerIndex = valueIndex % layerSize; |
| deInt32 x = inLayerIndex % m_config.width; |
| deInt32 y = (inLayerIndex - x) / m_config.width; |
| deInt32 x1 = m_config.renderArea.offset.x; |
| deInt32 y1 = m_config.renderArea.offset.y; |
| deInt32 x2 = x1 + m_config.renderArea.extent.width; |
| deInt32 y2 = y1 + m_config.renderArea.extent.height; |
| if ((x < x1) || (x >= x2) || (y < y1) || (y >= y2)) |
| { |
| if (stencil != m_config.clearValue.stencil) |
| { |
| m_context.getTestContext().getLog() |
| << TestLog::Message << "(" << x << ", " << y << ", layer: " << layerIndex |
| << ") is outside of render area but stencil value is: " |
| << stencil << " (expected " << m_config.clearValue.stencil << ")" << TestLog::EndMessage; |
| return false; |
| } |
| |
| // value is correct, go to next one |
| continue; |
| } |
| |
| if (stencil != expectedValue) |
| { |
| m_context.getTestContext().getLog() << TestLog::Message |
| << "At (" << x << ", " << y << ", layer: " << layerIndex |
| << ") stencil value is: " << static_cast<deUint32>(stencil) |
| << " expected: " << static_cast<deUint32>(expectedValue) |
| << TestLog::EndMessage; |
| return false; |
| } |
| } |
| m_context.getTestContext().getLog() << TestLog::Message |
| << "Stencil value is " |
| << static_cast<deUint32>(expectedValue) |
| << TestLog::EndMessage; |
| |
| return true; |
| } |
| |
| tcu::TestStatus DepthStencilResolveTest::iterate (void) |
| { |
| submit(); |
| |
| bool result = false; |
| if (m_config.verifyBuffer == VB_DEPTH) |
| result = verifyDepth(); |
| else |
| result = verifyStencil(); |
| |
| if (result) |
| return tcu::TestStatus::pass("Pass"); |
| return tcu::TestStatus::fail("Fail"); |
| } |
| |
| struct Programs |
| { |
| void init (vk::SourceCollections& dst, TestConfig config) const |
| { |
| // geometry shader is only needed in multi-layer framebuffer resolve tests |
| if (config.imageLayers > 1) |
| { |
| const deUint32 layerCount = 3; |
| |
| std::ostringstream src; |
| src << "#version 450\n" |
| << "highp float;\n" |
| << "\n" |
| << "layout(triangles) in;\n" |
| << "layout(triangle_strip, max_vertices = " << 3 * 2 * layerCount << ") out;\n" |
| << "\n" |
| << "in gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "} gl_in[];\n" |
| << "\n" |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "};\n" |
| << "\n" |
| << "void main (void) {\n" |
| << " for (int layerNdx = 0; layerNdx < " << layerCount << "; ++layerNdx) {\n" |
| << " for(int vertexNdx = 0; vertexNdx < gl_in.length(); vertexNdx++) {\n" |
| << " gl_Position = gl_in[vertexNdx].gl_Position;\n" |
| << " gl_Layer = layerNdx;\n" |
| << " EmitVertex();\n" |
| << " };\n" |
| << " EndPrimitive();\n" |
| << " };\n" |
| << "}\n"; |
| |
| dst.glslSources.add("quad-geom") << glu::GeometrySource(src.str()); |
| } |
| |
| dst.glslSources.add("quad-vert") << glu::VertexSource( |
| "#version 450\n" |
| "out gl_PerVertex {\n" |
| "\tvec4 gl_Position;\n" |
| "};\n" |
| "highp float;\n" |
| "void main (void) {\n" |
| "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" |
| "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" |
| "}\n"); |
| |
| if (config.verifyBuffer == VB_DEPTH) |
| { |
| dst.glslSources.add("quad-frag") << glu::FragmentSource( |
| "#version 450\n" |
| "precision highp float;\n" |
| "precision highp int;\n" |
| "void main (void)\n" |
| "{\n" |
| " float sampleIndex = float(gl_SampleID);\n" // sampleIndex is integer in range <0, 63> |
| " float valueIndex = round(mod(sampleIndex, 4.0));\n" // limit possible depth values - count to 4 |
| " float value = valueIndex + 2.0;\n" // value is one of [2, 3, 4, 5] |
| " value = round(exp2(value));\n" // value is one of [4, 8, 16, 32] |
| " bool condition = (int(value) == 8);\n" // select second sample value (to make it smallest) |
| " value = round(value - float(condition) * 6.0);\n" // value is one of [4, 2, 16, 32] |
| " gl_FragDepth = value / 100.0;\n" // sample depth is one of [0.04, 0.02, 0.16, 0.32] |
| "}\n"); |
| } |
| else |
| { |
| dst.glslSources.add("quad-frag") << glu::FragmentSource( |
| "#version 450\n" |
| "precision highp float;\n" |
| "precision highp int;\n" |
| "layout(push_constant) uniform PushConstant {\n" |
| " highp int sampleID;\n" |
| "} pushConstants;\n" |
| "void main (void)\n" |
| "{\n" |
| " if(gl_SampleID != pushConstants.sampleID)\n" |
| " discard;\n" |
| " gl_FragDepth = 0.5;\n" |
| "}\n"); |
| } |
| } |
| }; |
| |
| void initTests (tcu::TestCaseGroup* group) |
| { |
| typedef InstanceFactory1<DepthStencilResolveTest, TestConfig, Programs> DSResolveTestInstance; |
| |
| struct FormatData |
| { |
| VkFormat format; |
| const char* name; |
| bool hasDepth; |
| bool hasStencil; |
| }; |
| FormatData formats[] = |
| { |
| { VK_FORMAT_D16_UNORM, "d16_unorm", true, false }, |
| { VK_FORMAT_X8_D24_UNORM_PACK32, "x8_d24_unorm_pack32", true, false }, |
| { VK_FORMAT_D32_SFLOAT, "d32_sfloat", true, false }, |
| { VK_FORMAT_S8_UINT, "s8_uint", false, true }, |
| { VK_FORMAT_D16_UNORM_S8_UINT, "d16_unorm_s8_uint", true, true }, |
| { VK_FORMAT_D24_UNORM_S8_UINT, "d24_unorm_s8_uint", true, true }, |
| { VK_FORMAT_D32_SFLOAT_S8_UINT, "d32_sfloat_s8_uint", true, true }, |
| }; |
| |
| struct ResolveModeData |
| { |
| VkResolveModeFlagBitsKHR flag; |
| std::string name; |
| }; |
| ResolveModeData resolveModes[] = |
| { |
| { VK_RESOLVE_MODE_NONE_KHR, "none" }, |
| { VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR, "zero" }, |
| { VK_RESOLVE_MODE_AVERAGE_BIT_KHR, "average" }, |
| { VK_RESOLVE_MODE_MIN_BIT_KHR, "min" }, |
| { VK_RESOLVE_MODE_MAX_BIT_KHR, "max" }, |
| }; |
| |
| struct ImageTestData |
| { |
| const char* groupName; |
| deUint32 width; |
| deUint32 height; |
| deUint32 imageLayers; |
| VkRect2D renderArea; |
| VkClearDepthStencilValue clearValue; |
| }; |
| |
| // NOTE: tests cant be executed for 1D and 3D images: |
| // 1D images are not tested because acording to specyfication sampleCounts |
| // will be set to VK_SAMPLE_COUNT_1_BIT when type is not VK_IMAGE_TYPE_2D |
| // 3D images are not tested because VkFramebufferCreateInfo specification |
| // states that: each element of pAttachments that is a 2D or 2D array image |
| // view taken from a 3D image must not be a depth/stencil format |
| ImageTestData imagesTestData[] = |
| { |
| { "image_2d_32_32", 32, 32, 1, {{ 0, 0}, {32, 32}}, {0.000f, 0x00} }, |
| { "image_2d_8_32", 8, 32, 1, {{ 1, 1}, { 6, 30}}, {0.123f, 0x01} }, |
| { "image_2d_49_13", 49, 13, 1, {{10, 5}, {20, 8}}, {1.000f, 0x05} }, |
| { "image_2d_5_1", 5, 1, 1, {{ 0, 0}, { 5, 1}}, {0.500f, 0x00} }, |
| { "image_2d_17_1", 17, 1, 1, {{ 1, 0}, {15, 1}}, {0.789f, 0xfa} }, |
| }; |
| const deUint32 sampleCounts[] = |
| { |
| 2u, 4u, 8u, 16u, 32u, 64u |
| }; |
| const float depthExpectedValue[][6] = |
| { |
| // 2 samples 4 8 16 32 64 |
| { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, // RESOLVE_MODE_NONE - expect clear value |
| { 0.04f, 0.04f, 0.04f, 0.04f, 0.04f, 0.04f }, // RESOLVE_MODE_SAMPLE_ZERO_BIT |
| { 0.03f, 0.135f, 0.135f, 0.135f, 0.135f, 0.135f }, // RESOLVE_MODE_AVERAGE_BIT |
| { 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f }, // RESOLVE_MODE_MIN_BIT |
| { 0.04f, 0.32f, 0.32f, 0.32f, 0.32f, 0.32f }, // RESOLVE_MODE_MAX_BIT |
| }; |
| const deUint8 stencilExpectedValue[][6] = |
| { |
| // 2 samples 4 8 16 32 64 |
| { 0u, 0u, 0u, 0u, 0u, 0u }, // RESOLVE_MODE_NONE - expect clear value |
| { 1u, 1u, 1u, 1u, 1u, 1u }, // RESOLVE_MODE_SAMPLE_ZERO_BIT |
| { 0u, 0u, 0u, 0u, 0u, 0u }, // RESOLVE_MODE_AVERAGE_BIT - not supported |
| { 1u, 1u, 1u, 1u, 1u, 1u }, // RESOLVE_MODE_MIN_BIT |
| { 255u, 255u, 255u, 255u, 255u, 255u }, // RESOLVE_MODE_MAX_BIT |
| }; |
| |
| tcu::TestContext& testCtx(group->getTestContext()); |
| |
| // iterate over image data |
| for (deUint32 imageDataNdx = 0; imageDataNdx < DE_LENGTH_OF_ARRAY(imagesTestData); imageDataNdx++) |
| { |
| ImageTestData imageData = imagesTestData[imageDataNdx]; |
| |
| // create test group for image data |
| de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, imageData.groupName, imageData.groupName)); |
| |
| // iterate over sampleCounts |
| for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++) |
| { |
| const deUint32 sampleCount (sampleCounts[sampleCountNdx]); |
| const std::string sampleName ("samples_" + de::toString(sampleCount)); |
| |
| // create test group for sample count |
| de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, sampleName.c_str(), sampleName.c_str())); |
| |
| // iterate over depth/stencil formats |
| for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) |
| { |
| const FormatData& formatData = formats[formatNdx]; |
| VkFormat format = formatData.format; |
| const char* formatName = formatData.name; |
| const bool hasDepth = formatData.hasDepth; |
| const bool hasStencil = formatData.hasStencil; |
| VkImageAspectFlags aspectFlags = (hasDepth * VK_IMAGE_ASPECT_DEPTH_BIT) | |
| (hasStencil * VK_IMAGE_ASPECT_STENCIL_BIT); |
| |
| // create test group for format |
| de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, formatName, formatName)); |
| |
| // iterate over depth resolve modes |
| for (size_t depthResolveModeNdx = 0; depthResolveModeNdx < DE_LENGTH_OF_ARRAY(resolveModes); depthResolveModeNdx++) |
| { |
| // iterate over stencil resolve modes |
| for (size_t stencilResolveModeNdx = 0; stencilResolveModeNdx < DE_LENGTH_OF_ARRAY(resolveModes); stencilResolveModeNdx++) |
| { |
| // there is no average resolve mode for stencil - go to next iteration |
| ResolveModeData& sResolve = resolveModes[stencilResolveModeNdx]; |
| if (sResolve.flag == VK_RESOLVE_MODE_AVERAGE_BIT_KHR) |
| continue; |
| |
| // if pDepthStencilResolveAttachment is not NULL and does not have the value VK_ATTACHMENT_UNUSED, |
| // depthResolveMode and stencilResolveMode must not both be VK_RESOLVE_MODE_NONE_KHR |
| ResolveModeData& dResolve = resolveModes[depthResolveModeNdx]; |
| if ((dResolve.flag == VK_RESOLVE_MODE_NONE_KHR) && (sResolve.flag == VK_RESOLVE_MODE_NONE_KHR)) |
| continue; |
| |
| // If there is no depth, the depth resolve mode should be NONE, or |
| // match the stencil resolve mode. |
| if (!hasDepth && (dResolve.flag != VK_RESOLVE_MODE_NONE_KHR) && |
| (dResolve.flag != sResolve.flag)) |
| continue; |
| |
| // If there is no stencil, the stencil resmove mode should be NONE, or |
| // match the depth resolve mode. |
| if (!hasStencil && (sResolve.flag != VK_RESOLVE_MODE_NONE_KHR) && |
| (dResolve.flag != sResolve.flag)) |
| continue; |
| |
| std::string baseName = "depth_" + dResolve.name + "_stencil_" + sResolve.name; |
| |
| if (hasDepth) |
| { |
| std::string name = baseName + "_testing_depth"; |
| const char* testName = name.c_str(); |
| float expectedValue = depthExpectedValue[depthResolveModeNdx][sampleCountNdx]; |
| |
| const TestConfig testConfig = |
| { |
| format, |
| imageData.width, |
| imageData.height, |
| 1u, |
| 1u, |
| 0u, |
| imageData.renderArea, |
| aspectFlags, |
| sampleCount, |
| dResolve.flag, |
| sResolve.flag, |
| VB_DEPTH, |
| imageData.clearValue, |
| expectedValue, |
| 0u |
| }; |
| formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig)); |
| } |
| if (hasStencil) |
| { |
| std::string name = baseName + "_testing_stencil"; |
| const char* testName = name.c_str(); |
| deUint8 expectedValue = stencilExpectedValue[stencilResolveModeNdx][sampleCountNdx]; |
| |
| const TestConfig testConfig = |
| { |
| format, |
| imageData.width, |
| imageData.height, |
| 1u, |
| 1u, |
| 0u, |
| imageData.renderArea, |
| aspectFlags, |
| sampleCount, |
| dResolve.flag, |
| sResolve.flag, |
| VB_STENCIL, |
| imageData.clearValue, |
| 0.0f, |
| expectedValue |
| }; |
| formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig)); |
| } |
| } |
| } |
| |
| sampleGroup->addChild(formatGroup.release()); |
| } |
| |
| imageGroup->addChild(sampleGroup.release()); |
| } |
| |
| group->addChild(imageGroup.release()); |
| } |
| |
| { |
| // layered texture tests are done for all stencil modes and depth modes - not all combinations |
| // Test checks if all layer are resolved in multi-layered framebuffer and if we can have a framebuffer |
| // which starts at a layer other than zero. Both parts are tested together by rendering to layers |
| // 4-6 and resolving to layers 1-3. |
| ImageTestData layeredTextureTestData = |
| { |
| "image_2d_16_64_6", 16, 64, 6, {{ 10, 10}, {6, 54}}, {1.0f, 0x0} |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, layeredTextureTestData.groupName, layeredTextureTestData.groupName)); |
| |
| for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++) |
| { |
| const deUint32 sampleCount (sampleCounts[sampleCountNdx]); |
| const std::string sampleName ("samples_" + de::toString(sampleCount)); |
| |
| // create test group for sample count |
| de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, sampleName.c_str(), sampleName.c_str())); |
| |
| // iterate over depth/stencil formats |
| for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) |
| { |
| const FormatData& formatData = formats[formatNdx]; |
| VkFormat format = formatData.format; |
| const char* formatName = formatData.name; |
| const bool hasDepth = formatData.hasDepth; |
| const bool hasStencil = formatData.hasStencil; |
| VkImageAspectFlags aspectFlags = (hasDepth * VK_IMAGE_ASPECT_DEPTH_BIT) | |
| (hasStencil * VK_IMAGE_ASPECT_STENCIL_BIT); |
| |
| // create test group for format |
| de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, formatName, formatName)); |
| |
| for (size_t resolveModeNdx = 0; resolveModeNdx < DE_LENGTH_OF_ARRAY(resolveModes); resolveModeNdx++) |
| { |
| ResolveModeData& mode = resolveModes[resolveModeNdx]; |
| |
| if (hasDepth) |
| { |
| std::string name = "depth_" + mode.name; |
| const char* testName = name.c_str(); |
| float expectedValue = depthExpectedValue[resolveModeNdx][sampleCountNdx]; |
| const TestConfig testConfig = |
| { |
| format, |
| layeredTextureTestData.width, |
| layeredTextureTestData.height, |
| layeredTextureTestData.imageLayers, |
| 3u, |
| 0u, |
| layeredTextureTestData.renderArea, |
| aspectFlags, |
| sampleCount, |
| mode.flag, |
| VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR, |
| VB_DEPTH, |
| layeredTextureTestData.clearValue, |
| expectedValue, |
| 0u |
| }; |
| formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig)); |
| } |
| |
| // there is no average resolve mode for stencil - go to next iteration |
| if (mode.flag == VK_RESOLVE_MODE_AVERAGE_BIT_KHR) |
| continue; |
| |
| if (hasStencil) |
| { |
| std::string name = "stencil_" + mode.name; |
| const char* testName = name.c_str(); |
| deUint8 expectedValue = stencilExpectedValue[resolveModeNdx][sampleCountNdx]; |
| const TestConfig testConfig = |
| { |
| format, |
| layeredTextureTestData.width, |
| layeredTextureTestData.height, |
| layeredTextureTestData.imageLayers, |
| 3u, |
| 0u, |
| layeredTextureTestData.renderArea, |
| aspectFlags, |
| sampleCount, |
| VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR, |
| mode.flag, |
| VB_STENCIL, |
| layeredTextureTestData.clearValue, |
| 0.0f, |
| expectedValue |
| }; |
| formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig)); |
| } |
| } |
| sampleGroup->addChild(formatGroup.release()); |
| } |
| imageGroup->addChild(sampleGroup.release()); |
| } |
| |
| group->addChild(imageGroup.release()); |
| } |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createRenderPass2DepthStencilResolveTests (tcu::TestContext& testCtx) |
| { |
| return createTestGroup(testCtx, "depth_stencil_resolve", "Depth/stencil resolve tests", initTests); |
| } |
| |
| } // vkt |