blob: 5a297424d5594a8bbfd4e94b69bd296faea7275f [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Imagination Technologies Ltd.
*
* 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 Stencil Tests
*//*--------------------------------------------------------------------*/
#include "vktPipelineStencilTests.hpp"
#include "vktPipelineClearUtil.hpp"
#include "vktPipelineImageUtil.hpp"
#include "vktPipelineVertexUtil.hpp"
#include "vktPipelineReferenceRenderer.hpp"
#include "vktPipelineUniqueRandomIterator.hpp"
#include "vktTestCase.hpp"
#include "vkImageUtil.hpp"
#include "vkMemUtil.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 "deMemory.h"
#include "deRandom.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include <algorithm>
#include <sstream>
#include <vector>
namespace vkt
{
namespace pipeline
{
using namespace vk;
namespace
{
bool isSupportedDepthStencilFormat (const InstanceInterface& instanceInterface, VkPhysicalDevice device, VkFormat format)
{
VkFormatProperties formatProps;
instanceInterface.getPhysicalDeviceFormatProperties(device, format, &formatProps);
return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
}
class StencilOpStateUniqueRandomIterator : public UniqueRandomIterator<VkStencilOpState>
{
public:
StencilOpStateUniqueRandomIterator (int seed);
virtual ~StencilOpStateUniqueRandomIterator (void) {}
virtual VkStencilOpState getIndexedValue (deUint32 index);
private:
// Pre-calculated constants
const static deUint32 s_stencilOpsLength;
const static deUint32 s_stencilOpsLength2;
const static deUint32 s_stencilOpsLength3;
const static deUint32 s_compareOpsLength;
// Total number of cross-combinations of (stencilFailOp x stencilPassOp x stencilDepthFailOp x stencilCompareOp)
const static deUint32 s_totalStencilOpStates;
};
class StencilTest : public vkt::TestCase
{
public:
enum
{
QUAD_COUNT = 4
};
struct StencilStateConfig
{
deUint32 frontReadMask;
deUint32 frontWriteMask;
deUint32 frontRef;
deUint32 backReadMask;
deUint32 backWriteMask;
deUint32 backRef;
};
const static StencilStateConfig s_stencilStateConfigs[QUAD_COUNT];
const static float s_quadDepths[QUAD_COUNT];
StencilTest (tcu::TestContext& testContext,
const std::string& name,
const std::string& description,
VkFormat stencilFormat,
const VkStencilOpState& stencilOpStateFront,
const VkStencilOpState& stencilOpStateBack,
const bool colorAttachmentEnable,
const bool separateDepthStencilLayouts);
virtual ~StencilTest (void);
virtual void initPrograms (SourceCollections& sourceCollections) const;
virtual void checkSupport (Context& context) const;
virtual TestInstance* createInstance (Context& context) const;
private:
VkFormat m_stencilFormat;
const VkStencilOpState m_stencilOpStateFront;
const VkStencilOpState m_stencilOpStateBack;
const bool m_colorAttachmentEnable;
const bool m_separateDepthStencilLayouts;
};
class StencilTestInstance : public vkt::TestInstance
{
public:
StencilTestInstance (Context& context,
VkFormat stencilFormat,
const VkStencilOpState& stencilOpStatesFront,
const VkStencilOpState& stencilOpStatesBack,
const bool colorAttachmentEnable,
const bool separateDepthStencilLayouts);
virtual ~StencilTestInstance (void);
virtual tcu::TestStatus iterate (void);
private:
tcu::TestStatus verifyImage (void);
VkStencilOpState m_stencilOpStateFront;
VkStencilOpState m_stencilOpStateBack;
const bool m_colorAttachmentEnable;
const bool m_separateDepthStencilLayouts;
const tcu::UVec2 m_renderSize;
const VkFormat m_colorFormat;
const VkFormat m_stencilFormat;
VkImageSubresourceRange m_stencilImageSubresourceRange;
VkImageCreateInfo m_colorImageCreateInfo;
Move<VkImage> m_colorImage;
de::MovePtr<Allocation> m_colorImageAlloc;
Move<VkImage> m_stencilImage;
de::MovePtr<Allocation> m_stencilImageAlloc;
Move<VkImageView> m_colorAttachmentView;
Move<VkImageView> m_stencilAttachmentView;
Move<VkRenderPass> m_renderPass;
Move<VkFramebuffer> m_framebuffer;
Move<VkShaderModule> m_vertexShaderModule;
Move<VkShaderModule> m_fragmentShaderModule;
Move<VkBuffer> m_vertexBuffer;
std::vector<Vertex4RGBA> m_vertices;
de::MovePtr<Allocation> m_vertexBufferAlloc;
Move<VkPipelineLayout> m_pipelineLayout;
Move<VkPipeline> m_graphicsPipelines[StencilTest::QUAD_COUNT];
Move<VkCommandPool> m_cmdPool;
Move<VkCommandBuffer> m_cmdBuffer;
};
const VkStencilOp stencilOps[] =
{
VK_STENCIL_OP_KEEP,
VK_STENCIL_OP_ZERO,
VK_STENCIL_OP_REPLACE,
VK_STENCIL_OP_INCREMENT_AND_CLAMP,
VK_STENCIL_OP_DECREMENT_AND_CLAMP,
VK_STENCIL_OP_INVERT,
VK_STENCIL_OP_INCREMENT_AND_WRAP,
VK_STENCIL_OP_DECREMENT_AND_WRAP
};
const VkCompareOp compareOps[] =
{
VK_COMPARE_OP_NEVER,
VK_COMPARE_OP_LESS,
VK_COMPARE_OP_EQUAL,
VK_COMPARE_OP_LESS_OR_EQUAL,
VK_COMPARE_OP_GREATER,
VK_COMPARE_OP_NOT_EQUAL,
VK_COMPARE_OP_GREATER_OR_EQUAL,
VK_COMPARE_OP_ALWAYS
};
// StencilOpStateUniqueRandomIterator
const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength = DE_LENGTH_OF_ARRAY(stencilOps);
const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength2 = s_stencilOpsLength * s_stencilOpsLength;
const deUint32 StencilOpStateUniqueRandomIterator::s_stencilOpsLength3 = s_stencilOpsLength2 * s_stencilOpsLength;
const deUint32 StencilOpStateUniqueRandomIterator::s_compareOpsLength = DE_LENGTH_OF_ARRAY(compareOps);
const deUint32 StencilOpStateUniqueRandomIterator::s_totalStencilOpStates = s_stencilOpsLength3 * s_compareOpsLength;
StencilOpStateUniqueRandomIterator::StencilOpStateUniqueRandomIterator (int seed)
: UniqueRandomIterator<VkStencilOpState>(s_totalStencilOpStates, s_totalStencilOpStates, seed)
{
}
VkStencilOpState StencilOpStateUniqueRandomIterator::getIndexedValue (deUint32 index)
{
const deUint32 stencilCompareOpIndex = index / s_stencilOpsLength3;
const deUint32 stencilCompareOpSeqIndex = stencilCompareOpIndex * s_stencilOpsLength3;
const deUint32 stencilDepthFailOpIndex = (index - stencilCompareOpSeqIndex) / s_stencilOpsLength2;
const deUint32 stencilDepthFailOpSeqIndex = stencilDepthFailOpIndex * s_stencilOpsLength2;
const deUint32 stencilPassOpIndex = (index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex) / s_stencilOpsLength;
const deUint32 stencilPassOpSeqIndex = stencilPassOpIndex * s_stencilOpsLength;
const deUint32 stencilFailOpIndex = index - stencilCompareOpSeqIndex - stencilDepthFailOpSeqIndex - stencilPassOpSeqIndex;
const VkStencilOpState stencilOpState =
{
stencilOps[stencilFailOpIndex], // VkStencilOp failOp;
stencilOps[stencilPassOpIndex], // VkStencilOp passOp;
stencilOps[stencilDepthFailOpIndex], // VkStencilOp depthFailOp;
compareOps[stencilCompareOpIndex], // VkCompareOp compareOp;
0x0, // deUint32 compareMask;
0x0, // deUint32 writeMask;
0x0 // deUint32 reference;
};
return stencilOpState;
}
// StencilTest
const StencilTest::StencilStateConfig StencilTest::s_stencilStateConfigs[QUAD_COUNT] =
{
// frontReadMask frontWriteMask frontRef backReadMask backWriteMask backRef
{ 0xFF, 0xFF, 0xAB, 0xF0, 0xFF, 0xFF },
{ 0xFF, 0xF0, 0xCD, 0xF0, 0xF0, 0xEF },
{ 0xF0, 0x0F, 0xEF, 0xFF, 0x0F, 0xCD },
{ 0xF0, 0x01, 0xFF, 0xFF, 0x01, 0xAB }
};
const float StencilTest::s_quadDepths[QUAD_COUNT] =
{
0.1f,
0.0f,
0.3f,
0.2f
};
StencilTest::StencilTest (tcu::TestContext& testContext,
const std::string& name,
const std::string& description,
VkFormat stencilFormat,
const VkStencilOpState& stencilOpStateFront,
const VkStencilOpState& stencilOpStateBack,
const bool colorAttachmentEnable,
const bool separateDepthStencilLayouts)
: vkt::TestCase (testContext, name, description)
, m_stencilFormat (stencilFormat)
, m_stencilOpStateFront (stencilOpStateFront)
, m_stencilOpStateBack (stencilOpStateBack)
, m_colorAttachmentEnable (colorAttachmentEnable)
, m_separateDepthStencilLayouts (separateDepthStencilLayouts)
{
}
StencilTest::~StencilTest (void)
{
}
void StencilTest::checkSupport (Context& context) const
{
if (!isSupportedDepthStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice(), m_stencilFormat))
throw tcu::NotSupportedError(std::string("Unsupported depth/stencil format: ") + getFormatName(m_stencilFormat));
if (m_separateDepthStencilLayouts && !context.isDeviceFunctionalitySupported("VK_KHR_separate_depth_stencil_layouts"))
TCU_THROW(NotSupportedError, "VK_KHR_separate_depth_stencil_layouts is not supported");
}
TestInstance* StencilTest::createInstance (Context& context) const
{
return new StencilTestInstance(context, m_stencilFormat, m_stencilOpStateFront, m_stencilOpStateBack, m_colorAttachmentEnable, m_separateDepthStencilLayouts);
}
void StencilTest::initPrograms (SourceCollections& sourceCollections) const
{
if (m_colorAttachmentEnable)
{
sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec4 color;\n"
"layout(location = 0) out highp vec4 vtxColor;\n"
"void main (void)\n"
"{\n"
" gl_Position = position;\n"
" vtxColor = color;\n"
"}\n");
sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
"#version 310 es\n"
"layout(location = 0) in highp vec4 vtxColor;\n"
"layout(location = 0) out highp vec4 fragColor;\n"
"void main (void)\n"
"{\n"
" fragColor = vtxColor;\n"
"}\n");
}
else
{
sourceCollections.glslSources.add("color_vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec4 color;\n"
"void main (void)\n"
"{\n"
" gl_Position = position;\n"
"}\n");
sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
"#version 310 es\n"
"void main (void)\n"
"{\n"
"}\n");
}
}
// StencilTestInstance
StencilTestInstance::StencilTestInstance (Context& context,
VkFormat stencilFormat,
const VkStencilOpState& stencilOpStateFront,
const VkStencilOpState& stencilOpStateBack,
const bool colorAttachmentEnable,
const bool separateDepthStencilLayouts)
: vkt::TestInstance (context)
, m_stencilOpStateFront (stencilOpStateFront)
, m_stencilOpStateBack (stencilOpStateBack)
, m_colorAttachmentEnable (colorAttachmentEnable)
, m_separateDepthStencilLayouts (separateDepthStencilLayouts)
, m_renderSize (32, 32)
, m_colorFormat (colorAttachmentEnable ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_UNDEFINED)
, m_stencilFormat (stencilFormat)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
// Create color image
if (m_colorAttachmentEnable)
{
const VkImageCreateInfo colorImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_colorFormat, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_colorImageCreateInfo = colorImageParams;
m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo);
// Allocate and bind color image memory
m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
}
// Create stencil image
{
const VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
const VkImageCreateInfo stencilImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_stencilFormat, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
usageFlags, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_stencilImage = createImage(vk, vkDevice, &stencilImageParams);
// Allocate and bind stencil image memory
m_stencilImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_stencilImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_stencilImage, m_stencilImageAlloc->getMemory(), m_stencilImageAlloc->getOffset()));
const VkImageAspectFlags aspect = (mapVkFormat(m_stencilFormat).order == tcu::TextureFormat::DS ? VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT
: VK_IMAGE_ASPECT_STENCIL_BIT);
m_stencilImageSubresourceRange = makeImageSubresourceRange(aspect, 0u, stencilImageParams.mipLevels, 0u, stencilImageParams.arrayLayers);
}
// Create color attachment view
if (m_colorAttachmentEnable)
{
const VkImageViewCreateInfo colorAttachmentViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_colorImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_colorFormat, // VkFormat format;
componentMappingRGBA, // VkComponentMapping components;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
}
// Create stencil attachment view
{
const VkImageViewCreateInfo stencilAttachmentViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_stencilImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_stencilFormat, // VkFormat format;
componentMappingRGBA, // VkComponentMapping components;
m_stencilImageSubresourceRange, // VkImageSubresourceRange subresourceRange;
};
m_stencilAttachmentView = createImageView(vk, vkDevice, &stencilAttachmentViewParams);
}
// Create render pass
m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_stencilFormat);
// Create framebuffer
{
std::vector<VkImageView> attachmentBindInfos;
if (m_colorAttachmentEnable)
attachmentBindInfos.push_back(*m_colorAttachmentView);
attachmentBindInfos.push_back(*m_stencilAttachmentView);
const VkFramebufferCreateInfo framebufferParams =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkFramebufferCreateFlags flags;
*m_renderPass, // VkRenderPass renderPass;
(deUint32)attachmentBindInfos.size(), // deUint32 attachmentCount;
attachmentBindInfos.data(), // const VkImageView* pAttachments;
(deUint32)m_renderSize.x(), // deUint32 width;
(deUint32)m_renderSize.y(), // deUint32 height;
1u // deUint32 layers;
};
m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
}
// Create pipeline layout
{
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
0u, // deUint32 setLayoutCount;
DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
}
m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
// Create pipeline
{
const VkVertexInputBindingDescription vertexInputBindingDescription =
{
0u, // deUint32 binding;
sizeof(Vertex4RGBA), // deUint32 strideInBytes;
VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
};
const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
{
{
0u, // deUint32 location;
0u, // deUint32 binding;
VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
0u // deUint32 offsetInBytes;
},
{
1u, // deUint32 location;
0u, // deUint32 binding;
VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offsetInBytes;
}
};
const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineVertexInputStateCreateFlags flags;
1u, // deUint32 vertexBindingDescriptionCount;
&vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2u, // deUint32 vertexAttributeDescriptionCount;
vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const std::vector<VkViewport> viewports (1, makeViewport(m_renderSize));
const std::vector<VkRect2D> scissors (1, makeRect2D(m_renderSize));
const bool isDepthEnabled = (vk::mapVkFormat(m_stencilFormat).order != tcu::TextureFormat::S);
VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineDepthStencilStateCreateFlags flags;
isDepthEnabled, // VkBool32 depthTestEnable;
isDepthEnabled, // VkBool32 depthWriteEnable;
VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
false, // VkBool32 depthBoundsTestEnable;
true, // VkBool32 stencilTestEnable;
m_stencilOpStateFront, // VkStencilOpState front;
m_stencilOpStateBack, // VkStencilOpState back;
0.0f, // float minDepthBounds;
1.0f // float maxDepthBounds;
};
// Setup different stencil masks and refs in each quad
for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
{
const StencilTest::StencilStateConfig& config = StencilTest::s_stencilStateConfigs[quadNdx];
VkStencilOpState& front = depthStencilStateParams.front;
VkStencilOpState& back = depthStencilStateParams.back;
front.compareMask = config.frontReadMask;
front.writeMask = config.frontWriteMask;
front.reference = config.frontRef;
back.compareMask = config.backReadMask;
back.writeMask = config.backWriteMask;
back.reference = config.backRef;
m_graphicsPipelines[quadNdx] = makeGraphicsPipeline(vk, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayout, // const VkPipelineLayout pipelineLayout
*m_vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlModule
DE_NULL, // const VkShaderModule tessellationEvalModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*m_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
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
&depthStencilStateParams); // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
}
}
// Create vertex buffer
{
const VkBufferCreateInfo vertexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
1024u, // VkDeviceSize size;
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
m_vertices = createOverlappingQuads();
m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
// Adjust depths
for (int quadNdx = 0; quadNdx < 4; quadNdx++)
for (int vertexNdx = 0; vertexNdx < 6; vertexNdx++)
m_vertices[quadNdx * 6 + vertexNdx].position.z() = StencilTest::s_quadDepths[quadNdx];
// Load vertices into vertex buffer
deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
}
// Create command pool
m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
// Create command buffer
{
const VkImageMemoryBarrier colorImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkAccessFlags)0, // VkAccessFlags srcAccessMask;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
*m_colorImage, // VkImage image;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
VkImageSubresourceRange stencilImageBarrierSubresourceRange = m_stencilImageSubresourceRange;
VkImageLayout newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (m_separateDepthStencilLayouts)
{
stencilImageBarrierSubresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
newLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR;
}
const VkImageMemoryBarrier stencilImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkAccessFlags)0, // VkAccessFlags srcAccessMask;
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
newLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
*m_stencilImage, // VkImage image;
stencilImageBarrierSubresourceRange, // VkImageSubresourceRange subresourceRange;
};
std::vector<VkClearValue> attachmentClearValues;
std::vector<VkImageMemoryBarrier> imageLayoutBarriers;
if (m_colorAttachmentEnable)
{
attachmentClearValues.push_back(defaultClearValue(m_colorFormat));
imageLayoutBarriers.push_back(colorImageBarrier);
}
attachmentClearValues.push_back(defaultClearValue(m_stencilFormat));
imageLayoutBarriers.push_back(stencilImageBarrier);
m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
beginCommandBuffer(vk, *m_cmdBuffer, 0u);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0,
0u, DE_NULL, 0u, DE_NULL, (deUint32)imageLayoutBarriers.size(), imageLayoutBarriers.data());
beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), (deUint32)attachmentClearValues.size(), attachmentClearValues.data());
const VkDeviceSize quadOffset = (m_vertices.size() / StencilTest::QUAD_COUNT) * sizeof(Vertex4RGBA);
for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
{
VkDeviceSize vertexBufferOffset = quadOffset * quadNdx;
vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelines[quadNdx]);
vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
vk.cmdDraw(*m_cmdBuffer, (deUint32)(m_vertices.size() / StencilTest::QUAD_COUNT), 1, 0, 0);
}
endRenderPass(vk, *m_cmdBuffer);
endCommandBuffer(vk, *m_cmdBuffer);
}
}
StencilTestInstance::~StencilTestInstance (void)
{
}
tcu::TestStatus StencilTestInstance::iterate (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
return verifyImage();
}
tcu::TestStatus StencilTestInstance::verifyImage (void)
{
const tcu::TextureFormat tcuColorFormat = mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM);
const tcu::TextureFormat tcuStencilFormat = mapVkFormat(m_stencilFormat);
const ColorVertexShader vertexShader;
const ColorFragmentShader fragmentShader (tcuColorFormat, tcuStencilFormat);
const rr::Program program (&vertexShader, &fragmentShader);
ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
bool colorCompareOk = false;
bool stencilCompareOk = false;
// Render reference image
{
// Set depth state
rr::RenderState renderState(refRenderer.getViewportState(), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
renderState.fragOps.depthTestEnabled = true;
renderState.fragOps.depthFunc = mapVkCompareOp(VK_COMPARE_OP_LESS);
renderState.fragOps.stencilTestEnabled = true;
rr::StencilState& refStencilFront = renderState.fragOps.stencilStates[rr::FACETYPE_FRONT];
rr::StencilState& refStencilBack = renderState.fragOps.stencilStates[rr::FACETYPE_BACK];
refStencilFront.sFail = mapVkStencilOp(m_stencilOpStateFront.failOp);
refStencilFront.dpFail = mapVkStencilOp(m_stencilOpStateFront.depthFailOp);
refStencilFront.dpPass = mapVkStencilOp(m_stencilOpStateFront.passOp);
refStencilFront.func = mapVkCompareOp(m_stencilOpStateFront.compareOp);
refStencilBack.sFail = mapVkStencilOp(m_stencilOpStateBack.failOp);
refStencilBack.dpPass = mapVkStencilOp(m_stencilOpStateBack.passOp);
refStencilBack.dpFail = mapVkStencilOp(m_stencilOpStateBack.depthFailOp);
refStencilBack.func = mapVkCompareOp(m_stencilOpStateBack.compareOp);
// Reverse winding of vertices, as Vulkan screen coordinates start at upper left
std::vector<Vertex4RGBA> cwVertices(m_vertices);
for (size_t vertexNdx = 0; vertexNdx < cwVertices.size() - 2; vertexNdx += 3)
{
const Vertex4RGBA cwVertex1 = cwVertices[vertexNdx + 1];
cwVertices[vertexNdx + 1] = cwVertices[vertexNdx + 2];
cwVertices[vertexNdx + 2] = cwVertex1;
}
for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
{
refStencilFront.ref = (int)StencilTest::s_stencilStateConfigs[quadNdx].frontRef;
refStencilFront.compMask = StencilTest::s_stencilStateConfigs[quadNdx].frontReadMask;
refStencilFront.writeMask = StencilTest::s_stencilStateConfigs[quadNdx].frontWriteMask;
refStencilBack.ref = (int)StencilTest::s_stencilStateConfigs[quadNdx].backRef;
refStencilBack.compMask = StencilTest::s_stencilStateConfigs[quadNdx].backReadMask;
refStencilBack.writeMask = StencilTest::s_stencilStateConfigs[quadNdx].backWriteMask;
refRenderer.draw(renderState,
rr::PRIMITIVETYPE_TRIANGLES,
std::vector<Vertex4RGBA>(cwVertices.begin() + quadNdx * 6,
cwVertices.begin() + (quadNdx + 1) * 6));
}
}
// Compare result with reference image
if (m_colorAttachmentEnable)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
de::UniquePtr<tcu::TextureLevel> result (readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
colorCompareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
"IntImageCompare",
"Image comparison",
refRenderer.getAccess(),
result->getAccess(),
tcu::UVec4(2, 2, 2, 2),
tcu::IVec3(1, 1, 0),
true,
tcu::COMPARE_LOG_RESULT);
}
else
{
colorCompareOk = true;
}
// Compare stencil result with reference image
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
de::UniquePtr<tcu::TextureLevel> result (readStencilAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_stencilImage, m_stencilFormat, m_renderSize).release());
{
const tcu::PixelBufferAccess stencilAccess (tcu::getEffectiveDepthStencilAccess(refRenderer.getDepthStencilAccess(), tcu::Sampler::MODE_STENCIL));
stencilCompareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
"StencilImageCompare",
"Stencil image comparison",
stencilAccess,
result->getAccess(),
tcu::UVec4(2, 2, 2, 2),
tcu::IVec3(1, 1, 0),
true,
tcu::COMPARE_LOG_RESULT);
}
}
if (colorCompareOk && stencilCompareOk)
return tcu::TestStatus::pass("Result image matches reference");
else
return tcu::TestStatus::fail("Image mismatch");
}
// Utilities for test names
const char* getShortName (VkStencilOp stencilOp)
{
switch (stencilOp)
{
case VK_STENCIL_OP_KEEP: return "keep";
case VK_STENCIL_OP_ZERO: return "zero";
case VK_STENCIL_OP_REPLACE: return "repl";
case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return "incc";
case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return "decc";
case VK_STENCIL_OP_INVERT: return "inv";
case VK_STENCIL_OP_INCREMENT_AND_WRAP: return "wrap";
case VK_STENCIL_OP_DECREMENT_AND_WRAP: return "decw";
default:
DE_FATAL("Invalid VkStencilOpState value");
}
return DE_NULL;
}
std::string getStencilStateSetDescription(const VkStencilOpState& stencilOpStateFront,
const VkStencilOpState& stencilOpStateBack)
{
std::ostringstream desc;
desc << "\nFront faces:\n" << stencilOpStateFront;
desc << "Back faces:\n" << stencilOpStateBack;
return desc.str();
}
std::string getFormatCaseName (VkFormat format)
{
const std::string fullName = getFormatName(format);
DE_ASSERT(de::beginsWith(fullName, "VK_FORMAT_"));
return de::toLower(fullName.substr(10));
}
} // anonymous
tcu::TestCaseGroup* createStencilTests (tcu::TestContext& testCtx)
{
const VkFormat stencilFormats[] =
{
VK_FORMAT_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT
};
DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(compareOps) == 8);
DE_STATIC_ASSERT(vk::VK_COMPARE_OP_LAST == 8);
static const char* compareOpNames[8] =
{
"comp_never",
"comp_less",
"comp_equal",
"comp_less_or_equal",
"comp_greater",
"comp_not_equal",
"comp_greater_or_equal",
"comp_always"
};
de::MovePtr<tcu::TestCaseGroup> stencilTests (new tcu::TestCaseGroup(testCtx, "stencil", "Stencil tests"));
de::MovePtr<tcu::TestCaseGroup> noColorAttachmentTests (new tcu::TestCaseGroup(testCtx, "nocolor", "Stencil tests with no color attachment"));
const bool colorAttachmentEnabled[] = { true, false };
for (deUint32 colorAttachmentEnabledIdx = 0; colorAttachmentEnabledIdx < DE_LENGTH_OF_ARRAY(colorAttachmentEnabled); colorAttachmentEnabledIdx++)
{
const bool colorEnabled = colorAttachmentEnabled[colorAttachmentEnabledIdx];
de::MovePtr<tcu::TestCaseGroup> formatTests (new tcu::TestCaseGroup(testCtx, "format", "Uses different stencil formats"));
StencilOpStateUniqueRandomIterator stencilOpItr (123);
for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(stencilFormats); formatNdx++)
{
const VkFormat stencilFormat = stencilFormats[formatNdx];
const bool hasDepth = tcu::hasDepthComponent(mapVkFormat(stencilFormat).order);
const bool hasStencil = tcu::hasStencilComponent(mapVkFormat(stencilFormat).order);
const int separateLayoutsLoopCount = (hasDepth && hasStencil) ? 2 : 1;
for (int separateDepthStencilLayouts = 0; separateDepthStencilLayouts < separateLayoutsLoopCount; ++separateDepthStencilLayouts)
{
const bool useSeparateDepthStencilLayouts = bool(separateDepthStencilLayouts);
de::MovePtr<tcu::TestCaseGroup> formatTest (new tcu::TestCaseGroup(testCtx,
(getFormatCaseName(stencilFormat) + ((useSeparateDepthStencilLayouts) ? "_separate_layouts" : "")).c_str(),
(std::string("Uses format ") + getFormatName(stencilFormat) + ((useSeparateDepthStencilLayouts) ? " with separate depth/stencil layouts" : "")).c_str()));
de::MovePtr<tcu::TestCaseGroup> stencilStateTests;
{
std::ostringstream desc;
desc << "Draws 4 quads with the following depths and dynamic stencil states: ";
for (int quadNdx = 0; quadNdx < StencilTest::QUAD_COUNT; quadNdx++)
{
const StencilTest::StencilStateConfig& stencilConfig = StencilTest::s_stencilStateConfigs[quadNdx];
desc << "(" << quadNdx << ") "
<< "z = " << StencilTest::s_quadDepths[quadNdx] << ", "
<< "frontReadMask = " << stencilConfig.frontReadMask << ", "
<< "frontWriteMask = " << stencilConfig.frontWriteMask << ", "
<< "frontRef = " << stencilConfig.frontRef << ", "
<< "backReadMask = " << stencilConfig.backReadMask << ", "
<< "backWriteMask = " << stencilConfig.backWriteMask << ", "
<< "backRef = " << stencilConfig.backRef;
}
stencilStateTests = de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "states", desc.str().c_str()));
}
stencilOpItr.reset();
for (deUint32 failOpNdx = 0u; failOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); failOpNdx++)
{
const std::string failOpName = std::string("fail_") + getShortName(stencilOps[failOpNdx]);
de::MovePtr<tcu::TestCaseGroup> failOpTest (new tcu::TestCaseGroup(testCtx, failOpName.c_str(), ""));
for (deUint32 passOpNdx = 0u; passOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); passOpNdx++)
{
const std::string passOpName = std::string("pass_") + getShortName(stencilOps[passOpNdx]);
de::MovePtr<tcu::TestCaseGroup> passOpTest (new tcu::TestCaseGroup(testCtx, passOpName.c_str(), ""));
for (deUint32 dFailOpNdx = 0u; dFailOpNdx < DE_LENGTH_OF_ARRAY(stencilOps); dFailOpNdx++)
{
const std::string dFailOpName = std::string("dfail_") + getShortName(stencilOps[dFailOpNdx]);
de::MovePtr<tcu::TestCaseGroup> dFailOpTest (new tcu::TestCaseGroup(testCtx, dFailOpName.c_str(), ""));
for (deUint32 compareOpNdx = 0u; compareOpNdx < DE_LENGTH_OF_ARRAY(compareOps); compareOpNdx++)
{
// Iterate front set of stencil state in ascending order
const VkStencilOpState stencilStateFront =
{
stencilOps[failOpNdx], // failOp
stencilOps[passOpNdx], // passOp
stencilOps[dFailOpNdx], // depthFailOp
compareOps[compareOpNdx], // compareOp
0x0, // compareMask
0x0, // writeMask
0x0 // reference
};
// Iterate back set of stencil state in random order
const VkStencilOpState stencilStateBack = stencilOpItr.next();
const std::string caseName = compareOpNames[compareOpNdx];
const std::string caseDesc = getStencilStateSetDescription(stencilStateFront, stencilStateBack);
dFailOpTest->addChild(new StencilTest(testCtx, caseName, caseDesc, stencilFormat, stencilStateFront, stencilStateBack, colorEnabled, useSeparateDepthStencilLayouts));
}
passOpTest->addChild(dFailOpTest.release());
}
failOpTest->addChild(passOpTest.release());
}
stencilStateTests->addChild(failOpTest.release());
}
formatTest->addChild(stencilStateTests.release());
formatTests->addChild(formatTest.release());
}
}
if (colorEnabled)
stencilTests->addChild(formatTests.release());
else
noColorAttachmentTests->addChild(formatTests.release());
}
stencilTests->addChild(noColorAttachmentTests.release());
return stencilTests.release();
}
} // pipeline
} // vkt