blob: 730b7c61a53211eba28443292638a987f145a692 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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>
#include <map>
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;
VkResolveModeFlagBits depthResolveMode;
VkResolveModeFlagBits stencilResolveMode;
VerifyBuffer verifyBuffer;
VkClearDepthStencilValue clearValue;
float depthExpectedValue;
deUint8 stencilExpectedValue;
bool separateDepthStencilLayouts;
bool unusedResolve;
tcu::Maybe<VkFormat> compatibleFormat;
bool sampleMask;
};
// Auxiliar class to group depth formats by compatibility in bit size and format. Note there is at most one alternative format for
// each given format as of the time this comment is being written, and the alternative (compatible) format for a given format can
// only remove aspects but not add them. That is, we cannot use a depth/stencil attachment to resolve a depth-only attachment.
//
// See:
// * VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03181
// * VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03182
class DepthCompatibilityManager
{
public:
DepthCompatibilityManager ()
: m_compatibleFormats()
{
m_compatibleFormats[VK_FORMAT_D32_SFLOAT_S8_UINT] = VK_FORMAT_D32_SFLOAT;
m_compatibleFormats[VK_FORMAT_D16_UNORM_S8_UINT] = VK_FORMAT_D16_UNORM;
m_compatibleFormats[VK_FORMAT_D24_UNORM_S8_UINT] = VK_FORMAT_X8_D24_UNORM_PACK32;
}
VkFormat getAlternativeFormat (VkFormat format) const
{
const auto itr = m_compatibleFormats.find(format);
if (itr != end(m_compatibleFormats))
return itr->second;
return VK_FORMAT_UNDEFINED;
}
private:
std::map<VkFormat, VkFormat> m_compatibleFormats;
};
float get16bitDepthComponent(deUint8* pixelPtr)
{
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);
bool isSupportedFormat (Context& context, VkFormat format) const;
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 (VkFormat vkformat, deUint32 renderPassNo);
Move<VkRenderPass> createRenderPassCompatible (void);
Move<VkFramebuffer> createFramebuffer (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView);
Move<VkPipelineLayout> createRenderPipelineLayout (void);
Move<VkPipeline> createRenderPipeline (VkRenderPass renderPass, deUint32 renderPassNo, 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;
const Unique<VkCommandPool> m_commandPool;
VkImageSp m_multisampleImage;
AllocationSp m_multisampleImageMemory;
VkImageViewSp m_multisampleImageView;
VkImageSp m_singlesampleImage;
AllocationSp m_singlesampleImageMemory;
VkImageViewSp m_singlesampleImageView;
VkBufferSp m_buffer;
AllocationSp m_bufferMemory;
deUint32 m_numRenderPasses;
std::vector<Move<VkRenderPass>> m_renderPass;
Unique<VkRenderPass> m_renderPassCompatible;
Move<VkFramebuffer> m_framebuffer;
Unique<VkPipelineLayout> m_renderPipelineLayout;
std::vector<Move<VkPipeline>> m_renderPipeline;
};
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_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex()))
, m_multisampleImage (createImage(m_config.sampleCount, VK_IMAGE_USAGE_TRANSFER_SRC_BIT))
, m_multisampleImageMemory (createImageMemory(m_multisampleImage))
, m_multisampleImageView (createImageView(m_multisampleImage, 0u))
, m_singlesampleImage (createImage(1, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | (config.unusedResolve ? static_cast<vk::VkImageUsageFlags>(VK_IMAGE_USAGE_TRANSFER_DST_BIT) : 0u))))
, m_singlesampleImageMemory (createImageMemory(m_singlesampleImage))
, m_singlesampleImageView (createImageView(m_singlesampleImage, m_config.resolveBaseLayer))
, m_buffer (createBuffer())
, m_bufferMemory (createBufferMemory())
, m_numRenderPasses ((m_config.verifyBuffer == VB_DEPTH || !m_config.sampleMask) ? 1u : m_config.sampleCount)
, m_renderPassCompatible (createRenderPassCompatible())
, m_renderPipelineLayout (createRenderPipelineLayout())
{
for (deUint32 i = 0; i < m_numRenderPasses; i++)
{
m_renderPass.push_back(createRenderPass(m_config.format, i));
m_renderPipeline.push_back(createRenderPipeline(*m_renderPass[i], i, *m_renderPipelineLayout));
}
m_framebuffer = createFramebuffer(*m_renderPass[0], m_multisampleImageView, m_singlesampleImageView);
}
DepthStencilResolveTest::~DepthStencilResolveTest (void)
{
}
bool DepthStencilResolveTest::isFeaturesSupported()
{
m_context.requireDeviceFunctionality("VK_KHR_depth_stencil_resolve");
if (m_config.imageLayers > 1)
m_context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
if (m_config.separateDepthStencilLayouts)
m_context.requireDeviceFunctionality("VK_KHR_separate_depth_stencil_layouts");
VkPhysicalDeviceDepthStencilResolveProperties dsResolveProperties;
deMemset(&dsResolveProperties, 0, sizeof(VkPhysicalDeviceDepthStencilResolveProperties));
dsResolveProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
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
VkResolveModeFlagBits depthResolveMode = m_config.depthResolveMode;
VkResolveModeFlagBits stencilResolveMode = m_config.stencilResolveMode;
if ((depthResolveMode != VK_RESOLVE_MODE_NONE) &&
!(depthResolveMode & dsResolveProperties.supportedDepthResolveModes))
TCU_THROW(NotSupportedError, "Depth resolve mode not supported");
if ((stencilResolveMode != VK_RESOLVE_MODE_NONE) &&
!(stencilResolveMode & dsResolveProperties.supportedStencilResolveModes))
TCU_THROW(NotSupportedError, "Stencil resolve mode not supported");
// 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
if (dsResolveProperties.independentResolveNone)
{
if ((!dsResolveProperties.independentResolve) &&
(depthResolveMode != stencilResolveMode) &&
(depthResolveMode != VK_RESOLVE_MODE_NONE) &&
(stencilResolveMode != VK_RESOLVE_MODE_NONE))
TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes");
}
else if (!dsResolveProperties.independentResolve && (depthResolveMode != stencilResolveMode))
{
// when independentResolveNone and independentResolve are VK_FALSE then both modes must be the same
TCU_THROW(NotSupportedError, "Implementation doesn't support diferent resolve modes");
}
// Check alternative format support if needed.
if (m_config.compatibleFormat)
{
if (! isSupportedFormat(m_context, m_config.compatibleFormat.get()))
TCU_THROW(NotSupportedError, "Alternative image format for compatibility test not supported");
}
return true;
}
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(VkFormat vkformat, deUint32 renderPassNo)
{
const VkSampleCountFlagBits samples(sampleCountBitFromSampleCount(m_config.sampleCount));
VkImageLayout layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReferenceStencilLayoutKHR stencilLayout =
{
VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR,
DE_NULL,
VK_IMAGE_LAYOUT_UNDEFINED,
};
void * attachmentRefStencil = DE_NULL;
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
VkAttachmentDescriptionStencilLayoutKHR multisampleStencilFinalLayout =
{
VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR,
DE_NULL,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
};
VkAttachmentDescriptionStencilLayoutKHR singlesampleStencilFinalLayout =
{
VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR,
DE_NULL,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
};
void * multisampleAttachmentDescriptionStencil = DE_NULL;
void * singlesampleAttachmentDescriptionStencil = DE_NULL;
if (m_config.separateDepthStencilLayouts)
{
if (m_config.verifyBuffer == VB_DEPTH)
{
layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR;
stencilLayout.stencilLayout = VK_IMAGE_LAYOUT_GENERAL;
finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
multisampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
singlesampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR; // This aspect should be unused.
}
else
{
layout = m_config.sampleMask ? VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR : VK_IMAGE_LAYOUT_GENERAL;
stencilLayout.stencilLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR;
finalLayout = VK_IMAGE_LAYOUT_GENERAL; // This aspect should be unused.
multisampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
singlesampleStencilFinalLayout.stencilFinalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
attachmentRefStencil = &stencilLayout;
multisampleAttachmentDescriptionStencil = &multisampleStencilFinalLayout;
singlesampleAttachmentDescriptionStencil = &singlesampleStencilFinalLayout;
}
if (renderPassNo != 0)
{
multisampleStencilFinalLayout.stencilInitialLayout = stencilLayout.stencilLayout;
singlesampleStencilFinalLayout.stencilInitialLayout = stencilLayout.stencilLayout;
}
if (renderPassNo != m_numRenderPasses - 1)
{
finalLayout = layout;
multisampleStencilFinalLayout.stencilFinalLayout = layout;
singlesampleStencilFinalLayout.stencilFinalLayout = layout;
}
const AttachmentDescription2 multisampleAttachment // VkAttachmentDescription2
(
// VkStructureType sType;
multisampleAttachmentDescriptionStencil, // const void* pNext;
0u, // VkAttachmentDescriptionFlags flags;
m_config.format, // VkFormat format;
samples, // VkSampleCountFlagBits samples;
(renderPassNo == 0) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE,
(renderPassNo == 0) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_STORE,
(renderPassNo == 0) ? VK_IMAGE_LAYOUT_UNDEFINED : layout, // VkImageLayout initialLayout;
finalLayout // VkImageLayout finalLayout;
);
const AttachmentReference2 multisampleAttachmentRef // VkAttachmentReference2
(
// VkStructureType sType;
attachmentRefStencil, // const void* pNext;
0u, // deUint32 attachment;
layout, // VkImageLayout layout;
m_config.aspectFlag // VkImageAspectFlags aspectMask;
);
vk::VkImageLayout singleSampleInitialLayout = (m_config.unusedResolve ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED);
if (renderPassNo != 0)
singleSampleInitialLayout = layout;
if (m_config.separateDepthStencilLayouts && m_config.verifyBuffer == VB_STENCIL)
singlesampleStencilFinalLayout.stencilInitialLayout = singleSampleInitialLayout;
const tcu::TextureFormat format (mapVkFormat(vkformat));
VkImageAspectFlags aspectFlags =
((tcu::hasDepthComponent(format.order) ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_DEPTH_BIT) : 0u) |
(tcu::hasStencilComponent(format.order) ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_STENCIL_BIT) : 0u));
const AttachmentDescription2 singlesampleAttachment // VkAttachmentDescription2
(
// VkStructureType sType;
singlesampleAttachmentDescriptionStencil, // const void* pNext;
0u, // VkAttachmentDescriptionFlags flags;
vkformat, // 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;
singleSampleInitialLayout, // VkImageLayout initialLayout;
finalLayout // VkImageLayout finalLayout;
);
AttachmentReference2 singlesampleAttachmentRef // VkAttachmentReference2
(
// VkStructureType sType;
attachmentRefStencil, // const void* pNext;
((m_config.unusedResolve || renderPassNo != m_numRenderPasses - 1) ? VK_ATTACHMENT_UNUSED : 1u), // deUint32 attachment;
layout, // VkImageLayout layout;
aspectFlags // VkImageAspectFlags aspectMask;
);
std::vector<AttachmentDescription2> attachments;
attachments.push_back(multisampleAttachment);
attachments.push_back(singlesampleAttachment);
VkSubpassDescriptionDepthStencilResolve dsResolveDescription =
{
VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE,
DE_NULL, // const void* pNext;
m_config.depthResolveMode, // VkResolveModeFlagBits depthResolveMode;
m_config.stencilResolveMode, // VkResolveModeFlagBits stencilResolveMode;
&singlesampleAttachmentRef // VkAttachmentReference2 pDepthStencilResolveAttachment;
};
const SubpassDescription2 subpass // VkSubpassDescription2
(
// VkStructureType sType;
renderPassNo == m_numRenderPasses - 1 ? &dsResolveDescription : DE_NULL, // const void* pNext;
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // deUint32 viewMask;
0u, // deUint32 inputAttachmentCount;
DE_NULL, // const VkAttachmentReference2* pInputAttachments;
0u, // deUint32 colorAttachmentCount;
DE_NULL, // const VkAttachmentReference2* pColorAttachments;
DE_NULL, // const VkAttachmentReference2* pResolveAttachments;
&multisampleAttachmentRef, // const VkAttachmentReference2* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount;
DE_NULL // const deUint32* pPreserveAttachments;
);
const RenderPassCreateInfo2 renderPassCreator // VkRenderPassCreateInfo2
(
// VkStructureType sType;
DE_NULL, // const void* pNext;
(VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags;
(deUint32)attachments.size(), // deUint32 attachmentCount;
&attachments[0], // const VkAttachmentDescription2* pAttachments;
1u, // deUint32 subpassCount;
&subpass, // const VkSubpassDescription2* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL, // const VkSubpassDependency2* pDependencies;
0u, // deUint32 correlatedViewMaskCount;
DE_NULL // const deUint32* pCorrelatedViewMasks;
);
return renderPassCreator.createRenderPass(m_vkd, m_device);
}
// Checks format support.
// Note: we need the context because this is called from the constructor only after m_config has been set.
bool DepthStencilResolveTest::isSupportedFormat (Context& context, VkFormat format) const
{
const VkImageUsageFlags usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
| (m_config.unusedResolve ? VK_IMAGE_USAGE_TRANSFER_DST_BIT : static_cast<vk::VkImageUsageFlagBits>(0u));
VkImageFormatProperties props;
const auto& vki = context.getInstanceInterface();
const auto physicalDevice = context.getPhysicalDevice();
const auto formatCheck = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, 0u, &props);
return (formatCheck == VK_SUCCESS);
}
Move<VkRenderPass> DepthStencilResolveTest::createRenderPassCompatible (void)
{
// Early exit if we are not testing compatibility.
if (! m_config.compatibleFormat)
return {};
return createRenderPass(m_config.compatibleFormat.get(), 0);
}
Move<VkFramebuffer> DepthStencilResolveTest::createFramebuffer (VkRenderPass renderPass, VkImageViewSp multisampleImageView, VkImageViewSp singlesampleImageView)
{
std::vector<VkImageView> attachments;
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, deUint32 renderPassNo, 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 VkSampleMask samplemask[2] = {
renderPassNo < 32 ? (1u << renderPassNo) : 0,
renderPassNo < 32 ? 0 : (1u << (renderPassNo - 32)) };
const VkPipelineMultisampleStateCreateInfo multisampleState =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineMultisampleStateCreateFlags)0u,
sampleCountBitFromSampleCount(m_config.sampleCount),
VK_FALSE,
0.0f,
(m_config.sampleMask) ? &samplemask[0] : 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());
// When the depth/stencil resolve attachment is unused, it needs to be cleared outside
// the render pass so it has the expected values.
if (m_config.unusedResolve)
{
const tcu::TextureFormat format (mapVkFormat(m_config.format));
const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(m_vkd, m_device, *m_commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const vk::VkImageSubresourceRange imageRange =
{
((tcu::hasDepthComponent(format.order) ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_DEPTH_BIT) : 0u) |
(tcu::hasStencilComponent(format.order) ? static_cast<vk::VkImageAspectFlags>(vk::VK_IMAGE_ASPECT_STENCIL_BIT) : 0u)),
0u,
VK_REMAINING_MIP_LEVELS,
0u,
VK_REMAINING_ARRAY_LAYERS,
};
const vk::VkImageMemoryBarrier preBarrier =
{
vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
nullptr,
// src and dst access masks.
0,
vk::VK_ACCESS_TRANSFER_WRITE_BIT,
// old and new layouts.
vk::VK_IMAGE_LAYOUT_UNDEFINED,
vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
**m_singlesampleImage,
imageRange,
};
const vk::VkImageMemoryBarrier postBarrier =
{
vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
nullptr,
// src and dst access masks.
vk::VK_ACCESS_TRANSFER_WRITE_BIT,
0,
// old and new layouts.
vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
**m_singlesampleImage,
imageRange,
};
vk::beginCommandBuffer(m_vkd, commandBuffer.get());
m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preBarrier);
m_vkd.cmdClearDepthStencilImage(commandBuffer.get(), **m_singlesampleImage, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_config.clearValue, 1u, &imageRange);
m_vkd.cmdPipelineBarrier(commandBuffer.get(), vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &postBarrier);
vk::endCommandBuffer(m_vkd, commandBuffer.get());
vk::submitCommandsAndWait(m_vkd, m_device, m_context.getUniversalQueue(), commandBuffer.get());
}
const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const RenderpassSubpass2::SubpassBeginInfo subpassBeginInfo(DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
const RenderpassSubpass2::SubpassEndInfo subpassEndInfo(DE_NULL);
beginCommandBuffer(vkd, *commandBuffer);
bool testingDepth = (m_config.verifyBuffer == VB_DEPTH);
if (testingDepth)
{
{
VkClearValue clearValues[2];
clearValues[0].depthStencil = m_config.clearValue;
clearValues[1].depthStencil = m_config.clearValue;
const VkRenderPassBeginInfo beginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
DE_NULL,
(m_config.compatibleFormat ? *m_renderPassCompatible : *m_renderPass[0]),
*m_framebuffer,
{
{ 0u, 0u },
{ m_config.width, m_config.height }
},
2u,
clearValues
};
RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
}
// Render
vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline[0]);
vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
}
else
{
// Stencil
for (deUint32 i = 0; i < m_config.sampleCount; i++)
{
if (i == 0 || m_config.sampleMask)
{
VkClearValue clearValues[2];
clearValues[0].depthStencil = m_config.clearValue;
clearValues[1].depthStencil = m_config.clearValue;
const VkRenderPassBeginInfo beginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
DE_NULL,
(m_config.compatibleFormat ? *m_renderPassCompatible : *m_renderPass[i]),
*m_framebuffer,
{
{ 0u, 0u },
{ m_config.width, m_config.height }
},
2u,
clearValues
};
vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, 0, 0, 0, 0, 0);
RenderpassSubpass2::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
}
// For stencil we can set reference value for just one sample at a time
// so we need to do as many passes as there are samples, first half
// of samples is initialized with 1 and second half with 255
const deUint32 halfOfSamples = m_config.sampleCount >> 1;
deUint32 stencilReference = 1 + 254 * (i >= halfOfSamples);
vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline[m_config.sampleMask ? i : 0]);
vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(i), &i);
vkd.cmdSetStencilReference(*commandBuffer, VK_STENCIL_FRONT_AND_BACK, stencilReference);
vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
if (i == m_config.sampleCount - 1 || m_config.sampleMask)
RenderpassSubpass2::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
}
}
// Memory barriers between rendering and copying
{
const VkImageMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
DE_NULL,
// Note: as per the spec, depth/stencil *resolve* operations are synchronized using the color attachment write access.
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
**m_singlesampleImage,
{
(m_config.separateDepthStencilLayouts) ? VkImageAspectFlags(testingDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT) : 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,
{
VkImageAspectFlags(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, &region);
// 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)
{
// Invalidate allocation before attempting to read buffer memory.
invalidateAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_bufferMemory);
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 || m_config.unusedResolve)
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)
{
// Invalidate allocation before attempting to read buffer memory.
invalidateAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_bufferMemory);
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 || m_config.unusedResolve)
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
{
if (config.sampleMask)
{
dst.glslSources.add("quad-frag") << glu::FragmentSource(
"#version 450\n"
"precision highp float;\n"
"precision highp int;\n"
"void main (void)\n"
"{\n"
" gl_FragDepth = 0.5;\n"
"}\n");
}
else
{
dst.glslSources.add("quad-frag") << glu::FragmentSource(
"#version 450\n"
"precision highp float;\n"
"precision highp int;\n"
"layout(push_constant) uniform PushConstant {\n"
" highp int sampleID;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
" if(gl_SampleID != pushConstants.sampleID)\n"
" discard;\n"
" gl_FragDepth = 0.5;\n"
"}\n");
}
}
}
};
class PropertiesTestCase : public vkt::TestCase
{
public:
PropertiesTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
: vkt::TestCase(testCtx, name, description)
{}
virtual ~PropertiesTestCase (void) {}
virtual TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
};
class PropertiesTestInstance : public vkt::TestInstance
{
public:
PropertiesTestInstance (Context& context)
: vkt::TestInstance(context)
{}
virtual ~PropertiesTestInstance (void) {}
virtual tcu::TestStatus iterate (void);
};
TestInstance* PropertiesTestCase::createInstance (Context& context) const
{
return new PropertiesTestInstance(context);
}
void PropertiesTestCase::checkSupport (Context& context) const
{
context.requireDeviceFunctionality("VK_KHR_depth_stencil_resolve");
}
tcu::TestStatus PropertiesTestInstance::iterate (void)
{
vk::VkPhysicalDeviceDepthStencilResolvePropertiesKHR dsrProperties;
dsrProperties.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR;
dsrProperties.pNext = nullptr;
vk::VkPhysicalDeviceProperties2 properties2;
properties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties2.pNext = &dsrProperties;
m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &properties2);
if ((dsrProperties.supportedDepthResolveModes & vk::VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) == 0)
TCU_FAIL("supportedDepthResolveModes does not include VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR");
if ((dsrProperties.supportedStencilResolveModes & vk::VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) == 0)
TCU_FAIL("supportedStencilResolveModes does not include VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR");
if ((dsrProperties.supportedStencilResolveModes & vk::VK_RESOLVE_MODE_AVERAGE_BIT_KHR) != 0)
TCU_FAIL("supportedStencilResolveModes includes forbidden VK_RESOLVE_MODE_AVERAGE_BIT_KHR");
if (dsrProperties.independentResolve == VK_TRUE && dsrProperties.independentResolveNone != VK_TRUE)
TCU_FAIL("independentResolve supported but independentResolveNone not supported");
return tcu::TestStatus::pass("Pass");
}
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
{
VkResolveModeFlagBits flag;
std::string name;
};
ResolveModeData resolveModes[] =
{
{ VK_RESOLVE_MODE_NONE, "none" },
{ VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, "zero" },
{ VK_RESOLVE_MODE_AVERAGE_BIT, "average" },
{ VK_RESOLVE_MODE_MIN_BIT, "min" },
{ VK_RESOLVE_MODE_MAX_BIT, "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
};
const DepthCompatibilityManager compatManager;
tcu::TestContext& testCtx(group->getTestContext());
// Misc tests.
{
de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testCtx, "misc", "Miscellaneous depth/stencil resolve tests"));
miscGroup->addChild(new PropertiesTestCase(testCtx, "properties", "Check reported depth/stencil resolve properties"));
group->addChild(miscGroup.release());
}
// 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);
const int separateLayoutsLoopCount = (hasDepth && hasStencil) ? 2 : 1;
for (int separateDepthStencilLayouts = 0; separateDepthStencilLayouts < separateLayoutsLoopCount; ++separateDepthStencilLayouts)
{
const bool useSeparateDepthStencilLayouts = bool(separateDepthStencilLayouts);
const std::string groupName = std::string(formatName) + ((useSeparateDepthStencilLayouts) ? "_separate_layouts" : "");
// create test group for format
de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupName.c_str()));
// 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++)
{
for (int unusedIdx = 0; unusedIdx < 2; ++unusedIdx)
{
// there is no average resolve mode for stencil - go to next iteration
ResolveModeData& sResolve = resolveModes[stencilResolveModeNdx];
if (sResolve.flag == VK_RESOLVE_MODE_AVERAGE_BIT)
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) && (sResolve.flag == VK_RESOLVE_MODE_NONE))
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) &&
(dResolve.flag != sResolve.flag))
continue;
// If there is no stencil, the stencil resolve mode should be NONE, or
// match the depth resolve mode.
if (!hasStencil && (sResolve.flag != VK_RESOLVE_MODE_NONE) &&
(dResolve.flag != sResolve.flag))
continue;
const bool unusedResolve = (unusedIdx > 0);
std::string baseName = "depth_" + dResolve.name + "_stencil_" + sResolve.name;
if (unusedResolve)
baseName += "_unused_resolve";
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,
useSeparateDepthStencilLayouts,
unusedResolve,
tcu::nothing<VkFormat>(),
false
};
formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
if (sampleCountNdx == 0 && imageDataNdx == 0)
{
const auto compatibleFormat = compatManager.getAlternativeFormat(format);
if (compatibleFormat != VK_FORMAT_UNDEFINED)
{
std::string compatibilityTestName = "compatibility_" + name;
TestConfig compatibilityTestConfig = testConfig;
compatibilityTestConfig.compatibleFormat = tcu::just(compatibleFormat);
formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, compatibilityTestName.c_str(), compatibilityTestName.c_str(), compatibilityTestConfig));
}
}
}
if (hasStencil)
{
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,
useSeparateDepthStencilLayouts,
unusedResolve,
tcu::nothing<VkFormat>(),
false
};
formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName, testName, testConfig));
if (dResolve.flag == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT)
{
std::string samplemaskTestName = name + "_samplemask";
TestConfig samplemaskTestConfig = testConfig;
samplemaskTestConfig.sampleMask = true;
formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, samplemaskTestName.c_str(), samplemaskTestName.c_str(), samplemaskTestConfig));
}
// All formats with stencil and depth aspects have incompatible formats and sizes in the depth
// aspect, so their only alternative is the VK_FORMAT_S8_UINT format. Finally, that stencil-only
// format has no compatible formats that can be used.
if (sampleCountNdx == 0 && imageDataNdx == 0 && hasDepth)
{
std::string compatibilityTestName = "compatibility_" + name;
TestConfig compatibilityTestConfig = testConfig;
compatibilityTestConfig.compatibleFormat = tcu::just(VK_FORMAT_S8_UINT);
formatGroup->addChild(new DSResolveTestInstance(testCtx, tcu::NODETYPE_SELF_VALIDATE, compatibilityTestName.c_str(), compatibilityTestName.c_str(), compatibilityTestConfig));
}
}
}
}
}
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);
const int separateLayoutsLoopCount = (hasDepth && hasStencil) ? 2 : 1;
for (int separateDepthStencilLayouts = 0; separateDepthStencilLayouts < separateLayoutsLoopCount; ++separateDepthStencilLayouts)
{
const bool useSeparateDepthStencilLayouts = bool(separateDepthStencilLayouts);
const std::string groupName = std::string(formatName) + ((useSeparateDepthStencilLayouts) ? "_separate_layouts" : "");
// create test group for format
de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupName.c_str()));
for (size_t resolveModeNdx = 0; resolveModeNdx < DE_LENGTH_OF_ARRAY(resolveModes); resolveModeNdx++)
{
for (int unusedIdx = 0; unusedIdx < 2; ++unusedIdx)
{
ResolveModeData& mode = resolveModes[resolveModeNdx];
const bool unusedResolve = (unusedIdx > 0);
const std::string unusedSuffix = (unusedResolve ? "_unused_resolve" : "");
if (hasDepth)
{
std::string name = "depth_" + mode.name + unusedSuffix;
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,
VB_DEPTH,
layeredTextureTestData.clearValue,
expectedValue,
0u,
useSeparateDepthStencilLayouts,
unusedResolve,
tcu::nothing<VkFormat>(),
false
};
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)
continue;
if (hasStencil)
{
std::string name = "stencil_" + mode.name + unusedSuffix;
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,
mode.flag,
VB_STENCIL,
layeredTextureTestData.clearValue,
0.0f,
expectedValue,
useSeparateDepthStencilLayouts,
unusedResolve,
tcu::nothing<VkFormat>(),
false
};
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