/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 The Khronos Group Inc. * Copyright (c) 2019 Valve Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief VK_EXT_depth_range_unrestricted Tests *//*--------------------------------------------------------------------*/ #include "vktPipelineDepthRangeUnrestrictedTests.hpp" #include "vktPipelineVertexUtil.hpp" #include "vktPipelineClearUtil.hpp" #include "vktPipelineImageUtil.hpp" #include "vktPipelineReferenceRenderer.hpp" #include "vktTestCase.hpp" #include "vktTestCaseUtil.hpp" #include "vkMemUtil.hpp" #include "vkCmdUtil.hpp" #include "vkImageUtil.hpp" #include "vkBuilderUtil.hpp" #include "vkRefUtil.hpp" #include "vkQueryUtil.hpp" #include "vkTypeUtil.hpp" #include "vkObjUtil.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include "tcuImageCompare.hpp" #include #include namespace vkt { namespace pipeline { using namespace vk; namespace { enum testDynamicStaticMode { TEST_MODE_VIEWPORT_DEPTH_BOUNDS_STATIC = 0, TEST_MODE_VIEWPORT_DYNAMIC = 1, TEST_MODE_DEPTH_BOUNDS_DYNAMIC = 2, TEST_MODE_VIEWPORT_DEPTH_BOUNDS_DYNAMIC = 3, }; struct DepthRangeUnrestrictedParam { VkFormat depthFormat; VkBool32 testClearValueOnly; VkClearValue depthBufferClearValue; VkBool32 depthClampEnable; float wc; // Component W of the vertices deUint32 viewportDepthBoundsMode; float viewportMinDepth; float viewportMaxDepth; VkBool32 depthBoundsTestEnable; float minDepthBounds; float maxDepthBounds; VkCompareOp depthCompareOp; }; // helper functions std::string getFormatCaseName (vk::VkFormat format) { return de::toLower(de::toString(getFormatStr(format)).substr(10)); } std::string getCompareOpStringName (VkCompareOp compare) { return de::toLower(de::toString(getCompareOpStr(compare)).substr(3)); } const std::string generateTestName (struct DepthRangeUnrestrictedParam param) { std::ostringstream result; result << getFormatCaseName(param.depthFormat).c_str(); result << "_" << getCompareOpStringName(param.depthCompareOp).c_str(); result << "_clear_value_" << (int) param.depthBufferClearValue.depthStencil.depth; if (param.depthClampEnable == VK_FALSE) result << "_wc_" << (int) param.wc; if (param.viewportDepthBoundsMode & TEST_MODE_VIEWPORT_DYNAMIC) result << "_dynamic"; result << "_viewport_min_" << (int)param.viewportMinDepth << "_max_" << (int)param.viewportMaxDepth; if (param.depthBoundsTestEnable) { if (param.viewportDepthBoundsMode & TEST_MODE_DEPTH_BOUNDS_DYNAMIC) result << "_dynamic"; result << "_boundstest_min" << (int)param.minDepthBounds << "_max_" << (int)param.maxDepthBounds; } return result.str(); } const std::string generateTestDescription (struct DepthRangeUnrestrictedParam param) { std::string result("Test unrestricted depth ranges on viewport"); if (param.depthBoundsTestEnable) result += " , depth bounds test"; return result; } deBool 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) != 0u; } deBool isFloatingPointDepthFormat (VkFormat format) { switch (format) { case VK_FORMAT_D32_SFLOAT: case VK_FORMAT_D32_SFLOAT_S8_UINT: return DE_TRUE; case VK_FORMAT_D24_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM: return DE_FALSE; default: DE_FATAL("No depth format"); } return DE_FALSE; } deBool depthFormatHasStencilComponent (VkFormat format) { switch (format) { case VK_FORMAT_D32_SFLOAT_S8_UINT: case VK_FORMAT_D24_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM_S8_UINT: return DE_TRUE; case VK_FORMAT_D32_SFLOAT: case VK_FORMAT_D16_UNORM: return DE_FALSE; default: DE_FATAL("No depth format"); } return DE_FALSE; } deBool compareDepthResult (VkCompareOp compare, float depth, float clearValue) { deBool result = DE_FALSE; DE_ASSERT(compare <= VK_COMPARE_OP_ALWAYS && compare >= VK_COMPARE_OP_NEVER); switch (compare) { case VK_COMPARE_OP_ALWAYS: result = DE_TRUE; break; case VK_COMPARE_OP_NEVER: result = DE_FALSE; break; case VK_COMPARE_OP_EQUAL: result = depth == clearValue; break; case VK_COMPARE_OP_NOT_EQUAL: result = depth != clearValue; break; case VK_COMPARE_OP_GREATER: result = depth > clearValue; break; case VK_COMPARE_OP_GREATER_OR_EQUAL: result = depth >= clearValue; break; case VK_COMPARE_OP_LESS: result = depth < clearValue; break; case VK_COMPARE_OP_LESS_OR_EQUAL: result = depth <= clearValue; break; default: result = false; break; } return result; } static inline std::vector createPoints (float wc) { using tcu::Vec2; using tcu::Vec4; std::vector vertices; // Vertices are in the following positions of the image: // // ---------------------------------- // | | // | | // | 5 6 | // | | // | 1 2 | // | | // | | // | 3 0 | // | | // | 7 4 | // | | // | | // ---------------------------------- // // Vertex Depth Color // 0 0.0 white // 1 0.25 magenta // 2 -2.0 yellow // 3 2.0 red // 4 -5.0 black // 5 5.0 cyan // 6 10.0 blue // 7 -10.0 green // Depth values are constant, they don't depend on wc. const Vertex4RGBA vertex0 = { Vec4(0.25f * wc, 0.25f * wc, 0.0f, wc), Vec4(1.0f, 1.0f, 1.0f, 1.0) }; const Vertex4RGBA vertex1 = { Vec4(-0.25f * wc, -0.25f * wc, 0.25f, wc), Vec4(1.0f, 0.0f, 1.0f, 1.0) }; const Vertex4RGBA vertex2 = { Vec4(0.25f * wc, -0.25f * wc, -2.0f, wc), Vec4(1.0f, 1.0f, 0.0f, 1.0) }; const Vertex4RGBA vertex3 = { Vec4(-0.25f * wc, 0.25f * wc, 2.0f, wc), Vec4(1.0f, 0.0f, 0.0f, 1.0) }; const Vertex4RGBA vertex4 = { Vec4(0.5f * wc, 0.5f * wc, -5.0f, wc), Vec4(0.0f, 0.0f, 0.0f, 1.0) }; const Vertex4RGBA vertex5 = { Vec4(-0.5f * wc, -0.5f * wc, 5.0f, wc), Vec4(0.0f, 1.0f, 1.0f, 1.0) }; const Vertex4RGBA vertex6 = { Vec4(0.5f * wc, -0.5f * wc, 10.0f, wc), Vec4(0.0f, 0.0f, 1.0f, 1.0) }; const Vertex4RGBA vertex7 = { Vec4(-0.5f * wc, 0.5f * wc, -10.0f, wc), Vec4(0.0f, 1.0f, 0.0f, 1.0) }; vertices.push_back(vertex0); vertices.push_back(vertex1); vertices.push_back(vertex2); vertices.push_back(vertex3); vertices.push_back(vertex4); vertices.push_back(vertex5); vertices.push_back(vertex6); vertices.push_back(vertex7); return vertices; } template vkt::TestCase* newTestCase (tcu::TestContext& testContext, const DepthRangeUnrestrictedParam testParam) { return new Test(testContext, generateTestName(testParam).c_str(), generateTestDescription(testParam).c_str(), testParam); } Move createBufferAndBindMemory (Context& context, VkDeviceSize size, VkBufferUsageFlags usage, de::MovePtr* pAlloc) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice vkDevice = context.getDevice(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); const VkBufferCreateInfo vertexBufferParams = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkBufferCreateFlags flags; size, // VkDeviceSize size; usage, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyCount; &queueFamilyIndex // const deUint32* pQueueFamilyIndices; }; Move vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams); *pAlloc = context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); return vertexBuffer; } Move createImage2DAndBindMemory (Context& context, VkFormat format, deUint32 width, deUint32 height, VkImageUsageFlags usage, VkSampleCountFlagBits sampleCount, de::details::MovePtr* pAlloc) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice vkDevice = context.getDevice(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 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; format, // VkFormat format; { width, height, 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arraySize; sampleCount, // deUint32 samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; usage, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; }; Move image = createImage(vk, vkDevice, &colorImageParams); *pAlloc = context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(vkDevice, *image, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); return image; } Move makeRenderPass (const DeviceInterface& vk, const VkDevice device, const VkFormat colorFormat, const VkFormat depthStencilFormat, const VkAttachmentLoadOp loadOperationColor, const VkAttachmentLoadOp loadOperationDepthStencil) { const bool hasColor = colorFormat != VK_FORMAT_UNDEFINED; const bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED; const VkImageLayout initialLayoutColor = loadOperationColor == VK_ATTACHMENT_LOAD_OP_LOAD ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; const VkImageLayout initialLayoutDepthStencil = loadOperationDepthStencil == VK_ATTACHMENT_LOAD_OP_LOAD ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; const VkAttachmentDescription colorAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags colorFormat, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples loadOperationColor, // VkAttachmentLoadOp loadOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp initialLayoutColor, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout }; const VkAttachmentDescription depthStencilAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags depthStencilFormat, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples loadOperationDepthStencil, // VkAttachmentLoadOp loadOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp loadOperationDepthStencil, // VkAttachmentLoadOp stencilLoadOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp initialLayoutDepthStencil, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout }; std::vector attachmentDescriptions; if (hasColor) attachmentDescriptions.push_back(colorAttachmentDescription); if (hasDepthStencil) attachmentDescriptions.push_back(depthStencilAttachmentDescription); const VkAttachmentReference colorAttachmentRef = { 0u, // deUint32 attachment VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout }; const VkAttachmentReference depthStencilAttachmentRef = { hasColor ? 1u : 0u, // deUint32 attachment VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout }; const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint 0u, // deUint32 inputAttachmentCount DE_NULL, // const VkAttachmentReference* pInputAttachments hasColor ? 1u : 0u, // deUint32 colorAttachmentCount hasColor ? &colorAttachmentRef : DE_NULL, // const VkAttachmentReference* pColorAttachments DE_NULL, // const VkAttachmentReference* pResolveAttachments hasDepthStencil ? &depthStencilAttachmentRef : DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment 0u, // deUint32 preserveAttachmentCount DE_NULL // const deUint32* pPreserveAttachments }; const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags (deUint32)attachmentDescriptions.size(), // deUint32 attachmentCount attachmentDescriptions.size() > 0 ? &attachmentDescriptions[0] : DE_NULL, // const VkAttachmentDescription* pAttachments 1u, // deUint32 subpassCount &subpassDescription, // const VkSubpassDescription* pSubpasses 0u, // deUint32 dependencyCount DE_NULL // const VkSubpassDependency* pDependencies }; return createRenderPass(vk, device, &renderPassInfo, DE_NULL); } // Test Classes class DepthRangeUnrestrictedTestInstance : public vkt::TestInstance { public: DepthRangeUnrestrictedTestInstance (Context& context, const DepthRangeUnrestrictedParam param); virtual ~DepthRangeUnrestrictedTestInstance (void); virtual tcu::TestStatus iterate (void); protected: void prepareRenderPass (VkRenderPass renderPass, VkFramebuffer framebuffer, VkPipeline pipeline); void prepareCommandBuffer (void); Move buildPipeline (VkRenderPass renderpass); void bindShaderStage (VkShaderStageFlagBits stage, const char* sourceName, const char* entryName); tcu::TestStatus verifyTestResult (void); protected: const DepthRangeUnrestrictedParam m_param; deBool m_extensions; const tcu::UVec2 m_renderSize; const VkFormat m_colorFormat; Move m_pipelineLayout; Move m_depthImage; de::MovePtr m_depthImageAlloc; de::MovePtr m_colorImageAlloc; Move m_depthAttachmentView; VkImageMemoryBarrier m_imageLayoutBarriers[2]; Move m_vertexBuffer; de::MovePtr m_vertexBufferMemory; std::vector m_vertices; Move m_renderPass; Move m_cmdPool; Move m_cmdBuffer; Move m_colorImage; Move m_colorAttachmentView; Move m_framebuffer; Move m_pipeline; Move m_shaderModules[2]; deUint32 m_shaderStageCount; VkPipelineShaderStageCreateInfo m_shaderStageInfo[2]; }; void DepthRangeUnrestrictedTestInstance::bindShaderStage (VkShaderStageFlagBits stage, const char* sourceName, const char* entryName) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); // Create shader module deUint32* code = (deUint32*)m_context.getBinaryCollection().get(sourceName).getBinary(); deUint32 codeSize = (deUint32)m_context.getBinaryCollection().get(sourceName).getSize(); const VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkShaderModuleCreateFlags flags; codeSize, // deUintptr codeSize; code, // const deUint32* pCode; }; m_shaderModules[m_shaderStageCount] = createShaderModule(vk, vkDevice, &moduleCreateInfo); // Prepare shader stage info m_shaderStageInfo[m_shaderStageCount].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; m_shaderStageInfo[m_shaderStageCount].pNext = DE_NULL; m_shaderStageInfo[m_shaderStageCount].flags = 0u; m_shaderStageInfo[m_shaderStageCount].stage = stage; m_shaderStageInfo[m_shaderStageCount].module = *m_shaderModules[m_shaderStageCount]; m_shaderStageInfo[m_shaderStageCount].pName = entryName; m_shaderStageInfo[m_shaderStageCount].pSpecializationInfo = DE_NULL; m_shaderStageCount++; } Move DepthRangeUnrestrictedTestInstance::buildPipeline (VkRenderPass renderPass) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); // Create pipeline const VkVertexInputBindingDescription vertexInputBindingDescription = { 0u, // deUint32 binding; sizeof(Vertex4RGBA), // deUint32 strideInBytes; VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate 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 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineInputAssemblyStateCreateFlags flags; VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // VkPrimitiveTopology topology; VK_FALSE, // VkBool32 primitiveRestartEnable; }; const VkRect2D scissor = makeRect2D(m_renderSize); VkViewport viewport = makeViewport(m_renderSize); if (!(m_param.viewportDepthBoundsMode & TEST_MODE_VIEWPORT_DYNAMIC)) { viewport.minDepth = m_param.viewportMinDepth; viewport.maxDepth = m_param.viewportMaxDepth; } const VkPipelineViewportStateCreateInfo viewportStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineViewportStateCreateFlags flags; 1u, // deUint32 viewportCount; &viewport, // const VkViewport* pViewports; 1u, // deUint32 scissorCount; &scissor // const VkRect2D* pScissors; }; const VkPipelineRasterizationStateCreateInfo rasterStateParams = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineRasterizationStateCreateFlags flags; m_param.depthClampEnable, // VkBool32 depthClampEnable; VK_FALSE, // VkBool32 rasterizerDiscardEnable; VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; VK_FALSE, // VkBool32 depthBiasEnable; 0.0f, // float depthBiasConstantFactor; 0.0f, // float depthBiasClamp; 0.0f, // float depthBiasSlopeFactor; 1.0f, // float lineWidth; }; const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = { VK_FALSE, // VkBool32 blendEnable; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask; }; const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineColorBlendStateCreateFlags flags; VK_FALSE, // VkBool32 logicOpEnable; VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 1u, // deUint32 attachmentCount; &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; }; const VkPipelineMultisampleStateCreateInfo multisampleStateParams = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineMultisampleStateCreateFlags flags; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; VK_FALSE, // VkBool32 sampleShadingEnable; 0.0f, // float minSampleShading; DE_NULL, // const VkSampleMask* pSampleMask; VK_FALSE, // VkBool32 alphaToCoverageEnable; VK_FALSE, // VkBool32 alphaToOneEnable; }; float minDepthBounds = m_param.minDepthBounds; float maxDepthBounds = m_param.maxDepthBounds; if (m_param.viewportDepthBoundsMode & TEST_MODE_DEPTH_BOUNDS_DYNAMIC) { minDepthBounds = 0.0f; maxDepthBounds = 1.0f; } VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineDepthStencilStateCreateFlags flags; VK_TRUE, // VkBool32 depthTestEnable; VK_TRUE, // VkBool32 depthWriteEnable; m_param.depthCompareOp, // VkCompareOp depthCompareOp; m_param.depthBoundsTestEnable, // VkBool32 depthBoundsTestEnable; VK_FALSE, // VkBool32 stencilTestEnable; // VkStencilOpState front; { VK_STENCIL_OP_KEEP, // VkStencilOp failOp; VK_STENCIL_OP_KEEP, // VkStencilOp passOp; VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; 0u, // deUint32 compareMask; 0u, // deUint32 writeMask; 0u, // deUint32 reference; }, // VkStencilOpState back; { VK_STENCIL_OP_KEEP, // VkStencilOp failOp; VK_STENCIL_OP_KEEP, // VkStencilOp passOp; VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; 0u, // deUint32 compareMask; 0u, // deUint32 writeMask; 0u, // deUint32 reference; }, minDepthBounds, // float minDepthBounds; maxDepthBounds, // float maxDepthBounds; }; std::vector dynamicStates; if (m_param.viewportDepthBoundsMode & TEST_MODE_VIEWPORT_DYNAMIC) dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT); if (m_param.viewportDepthBoundsMode & TEST_MODE_DEPTH_BOUNDS_DYNAMIC) dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); const VkPipelineDynamicStateCreateInfo dynamicStateParams = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineDynamicStateCreateFlags)0u, // VkPipelineDynamicStateCreateFlags flags; (deUint32)dynamicStates.size(), // deUint32 dynamicStateCount; (const VkDynamicState*)dynamicStates.data() // const VkDynamicState* pDynamicStates; }; const VkGraphicsPipelineCreateInfo graphicsPipelineParams = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineCreateFlags flags; m_shaderStageCount, // deUint32 stageCount; m_shaderStageInfo, // const VkPipelineShaderStageCreateInfo* pStages; &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterState; &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState; *m_pipelineLayout, // VkPipelineLayout layout; renderPass, // VkRenderPass renderPass; 0u, // deUint32 subpass; DE_NULL, // VkPipeline basePipelineHandle; 0u, // deInt32 basePipelineIndex; }; return createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams); } void DepthRangeUnrestrictedTestInstance::prepareRenderPass (VkRenderPass renderPass, VkFramebuffer framebuffer, VkPipeline pipeline) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkClearValue attachmentClearValues[2] = { defaultClearValue(m_colorFormat), m_param.depthBufferClearValue, }; beginRenderPass(vk, *m_cmdBuffer, renderPass, framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), 2u, attachmentClearValues); vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkDeviceSize offsets = 0u; vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets); if (m_param.viewportDepthBoundsMode & TEST_MODE_VIEWPORT_DYNAMIC) { VkViewport viewport = makeViewport(m_renderSize); viewport.minDepth = m_param.viewportMinDepth; viewport.maxDepth = m_param.viewportMaxDepth; vk.cmdSetViewport(*m_cmdBuffer, 0u, 1u, &viewport); } if (m_param.viewportDepthBoundsMode & TEST_MODE_DEPTH_BOUNDS_DYNAMIC) vk.cmdSetDepthBounds(*m_cmdBuffer, m_param.minDepthBounds, m_param.maxDepthBounds); if (!m_vertices.empty() && !m_param.testClearValueOnly) vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1u, 0u, 0u); endRenderPass(vk, *m_cmdBuffer); } void DepthRangeUnrestrictedTestInstance::prepareCommandBuffer (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); 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_LATE_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(m_imageLayoutBarriers), m_imageLayoutBarriers); prepareRenderPass(*m_renderPass, *m_framebuffer, *m_pipeline); endCommandBuffer(vk, *m_cmdBuffer); } DepthRangeUnrestrictedTestInstance::DepthRangeUnrestrictedTestInstance (Context& context, const DepthRangeUnrestrictedParam param) : TestInstance (context) , m_param (param) , m_extensions (m_context.requireDeviceFunctionality("VK_EXT_depth_range_unrestricted")) , m_renderSize (tcu::UVec2(32,32)) , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) , m_shaderStageCount (0) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); if (!isSupportedDepthStencilFormat(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), param.depthFormat)) { throw tcu::NotSupportedError("Unsupported depth format"); } VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures(); if (param.depthClampEnable && features.depthClamp == DE_FALSE) { throw tcu::NotSupportedError("Unsupported feature: depthClamp"); } if (param.depthBoundsTestEnable && features.depthBounds == DE_FALSE) { throw tcu::NotSupportedError("Unsupported feature: depthBounds"); } // Create vertex buffer { m_vertexBuffer = createBufferAndBindMemory(m_context, 1024u, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &m_vertexBufferMemory); m_vertices = createPoints(m_param.wc); // Load vertices into vertex buffer deMemcpy(m_vertexBufferMemory->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA)); flushAlloc(vk, vkDevice, *m_vertexBufferMemory); } // Create render pass m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat, m_param.depthFormat, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); const VkComponentMapping ComponentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; // Create color image { m_colorImage = createImage2DAndBindMemory(m_context, m_colorFormat, m_renderSize.x(), m_renderSize.y(), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_SAMPLE_COUNT_1_BIT, &m_colorImageAlloc); } // Create depth image { m_depthImage = createImage2DAndBindMemory(m_context, m_param.depthFormat, m_renderSize.x(), m_renderSize.y(), VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_SAMPLE_COUNT_1_BIT, &m_depthImageAlloc); } deUint32 depthAspectBits = VK_IMAGE_ASPECT_DEPTH_BIT; if (depthFormatHasStencilComponent(param.depthFormat)) depthAspectBits |= VK_IMAGE_ASPECT_STENCIL_BIT; // Set up image layout transition barriers { VkImageMemoryBarrier colorImageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // 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, // deUint32 srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; *m_colorImage, // VkImage image; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; }; m_imageLayoutBarriers[0] = colorImageBarrier; VkImageMemoryBarrier depthImageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkAccessFlags srcAccessMask; VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; *m_depthImage, // VkImage image; { depthAspectBits, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; }; m_imageLayoutBarriers[1] = depthImageBarrier; } // Create color attachment view { 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 depth attachment view { const VkImageViewCreateInfo depthAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_depthImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; m_param.depthFormat, // VkFormat format; ComponentMappingRGBA, // VkComponentMapping components; { depthAspectBits, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; }; m_depthAttachmentView = createImageView(vk, vkDevice, &depthAttachmentViewParams); } // Create framebuffer { VkImageView attachmentBindInfos[2] = { *m_colorAttachmentView, *m_depthAttachmentView, }; const VkFramebufferCreateInfo framebufferParams = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 2u, // deUint32 attachmentCount; attachmentBindInfos, // const VkImageView* pAttachments; (deUint32)m_renderSize.x(), // deUint32 width; (deUint32)m_renderSize.y(), // deUint32 height; 1u, // deUint32 layers; }; m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); } // Bind shader stages { bindShaderStage(VK_SHADER_STAGE_VERTEX_BIT, "vert", "main"); bindShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, "frag", "main"); } // 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); } // Create pipeline m_pipeline = buildPipeline(*m_renderPass); // Create command pool m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); // Create command buffer m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); } DepthRangeUnrestrictedTestInstance::~DepthRangeUnrestrictedTestInstance (void) { } tcu::TestStatus DepthRangeUnrestrictedTestInstance::iterate (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); prepareCommandBuffer(); submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); return verifyTestResult(); } tcu::TestStatus DepthRangeUnrestrictedTestInstance::verifyTestResult (void) { deBool compareOk = DE_TRUE; const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); tcu::TestLog& log = m_context.getTestContext().getLog(); Allocator& allocator = m_context.getDefaultAllocator(); tcu::TextureLevel refImage (vk::mapVkFormat(m_colorFormat), 32, 32); float clearValue = m_param.depthBufferClearValue.depthStencil.depth; double epsilon = 1e-5; // For non-float depth formats, the value in the depth buffer is already clampled to the range [0, 1], which // includes the clear depth value. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) clearValue = de::min(de::max(clearValue, 0.0f), 1.0f); // Generate reference image { VkClearValue clearColor = defaultClearValue(m_colorFormat); tcu::Vec4 clearColorVec4 (clearColor.color.float32[0], clearColor.color.float32[1], clearColor.color.float32[2], clearColor.color.float32[3]); tcu::clear(refImage.getAccess(), clearColorVec4); for (std::vector::const_iterator vertex = m_vertices.begin(); vertex != m_vertices.end(); ++vertex) { if (m_param.depthClampEnable == VK_FALSE && (vertex->position.z() < 0.0f || vertex->position.z() > vertex->position.w())) continue; if (m_param.testClearValueOnly) continue; // Depth Clamp is enabled, then we clamp point depth to viewport's maxDepth and minDepth values, or [0.0f, 1.0f] is depth format is fixed-point. float scaling = ((vertex->position.z() / vertex->position.w()) * (m_param.viewportMaxDepth - m_param.viewportMinDepth)) + m_param.viewportMinDepth; float depth = de::min(de::max(scaling, m_param.viewportMinDepth), m_param.viewportMaxDepth); // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) depth = de::min(de::max(depth, 0.0f), 1.0f); if (compareDepthResult(m_param.depthCompareOp, depth, clearValue)) { deInt32 x = static_cast((((vertex->position.x() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.x() - 1)); deInt32 y = static_cast((((vertex->position.y() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.y() - 1)); refImage.getAccess().setPixel(vertex->color, x, y); } } } // Check the rendered image { de::MovePtr result = vkt::pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize); compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(), "IntImageCompare", "Image comparison", refImage.getAccess(), result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT); if (!compareOk) return tcu::TestStatus::fail("Image mismatch"); } // Check depth buffer contents { de::MovePtr depthResult = readDepthAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_depthImage, m_param.depthFormat, m_renderSize); if (m_param.testClearValueOnly) { compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "DepthImagecompare", "Depth image comparison", tcu::Vec4(clearValue, 0.0f, 0.0f, 1.0f), depthResult->getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::COMPARE_LOG_RESULT); if (!compareOk) return tcu::TestStatus::fail("Depth buffer mismatch"); else return tcu::TestStatus::pass("Result images matches references"); } log << tcu::TestLog::Message; for (std::vector::const_iterator vertex = m_vertices.begin(); vertex != m_vertices.end(); ++vertex) { deInt32 x = static_cast((((vertex->position.x() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.x() - 1)); deInt32 y = static_cast((((vertex->position.y() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.y() - 1)); tcu::Vec4 depth = depthResult->getAccess().getPixel(x, y); // Check depth values are valid if (depth.y() != 0.0f || depth.z() != 0.0f || depth.w() != 1.0f) { log << tcu::TestLog::Message << "Invalid depth buffer values for pixel (" << x << ", " << y << ") = (" << depth.x() << ", " << depth.y() << ", " << depth.z() << ", " << depth.w() << "." << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } // Check the case where depth clamping is disabled. if (m_param.depthClampEnable == VK_FALSE) { if ((vertex->position.z() < 0.0f || vertex->position.z() > vertex->position.w()) && fabs(clearValue - depth.x()) > epsilon) { log << tcu::TestLog::Message << "Error pixel (" << x << ", " << y << "). Depth value = " << depth << ", expected " << clearValue << "." << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } float expectedDepth = clearValue; if (vertex->position.z() <= vertex->position.w() && vertex->position.z() >= 0.0f) { // Assert we have a symmetric range around zero. DE_ASSERT(m_param.viewportMinDepth == (-m_param.viewportMaxDepth)); // Calculate the expected depth value: first translate the value to from [0.0f, 1.0f] to [-1.0f, 1.0f]. expectedDepth = 2 * (vertex->position.z() / vertex->position.w()) - 1.0f; // Now multiply by m_param.viewportMaxDepth to get the expected value. expectedDepth *= m_param.viewportMaxDepth; } // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) expectedDepth = de::min(de::max(expectedDepth, 0.0f), 1.0f); expectedDepth = compareDepthResult(m_param.depthCompareOp, expectedDepth, clearValue) ? expectedDepth : clearValue; if (fabs(expectedDepth - depth.x()) > epsilon) { log << tcu::TestLog::Message << "Error pixel (" << x << ", " << y << "). Depth value " << depth.x() << ", expected " << expectedDepth << ", error " << fabs(expectedDepth - depth.x()) << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } continue; } // Depth Clamp is enabled, then we clamp point depth to viewport's maxDepth and minDepth values, or 0.0f and 1.0f is format is not float. float scaling = (vertex->position.z() / vertex->position.w()) * (m_param.viewportMaxDepth - m_param.viewportMinDepth) + m_param.viewportMinDepth; float expectedDepth = de::min(de::max(scaling, m_param.viewportMinDepth), m_param.viewportMaxDepth); // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) expectedDepth = de::min(de::max(expectedDepth, 0.0f), 1.0f); expectedDepth = compareDepthResult(m_param.depthCompareOp, expectedDepth, clearValue) ? expectedDepth : clearValue; if (fabs(expectedDepth - depth.x()) > epsilon) { log << tcu::TestLog::Message << "Error pixel (" << x << ", " << y << "). Depth value " << depth.x() << ", expected " << expectedDepth << ", error " << fabs(expectedDepth - depth.x()) << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } } if (!compareOk) return tcu::TestStatus::fail("Depth buffer mismatch"); } return tcu::TestStatus::pass("Result images matches references"); } // Test Classes class DepthBoundsRangeUnrestrictedTestInstance : public DepthRangeUnrestrictedTestInstance { public: DepthBoundsRangeUnrestrictedTestInstance (Context& context, const DepthRangeUnrestrictedParam param); virtual ~DepthBoundsRangeUnrestrictedTestInstance (void); virtual tcu::TestStatus iterate (void); protected: tcu::TestStatus verifyTestResult (bool firstDraw); void prepareCommandBuffer (bool firstDraw); protected: Move m_renderPassSecondDraw; Move m_framebufferSecondDraw; Move m_pipelineSecondDraw; std::vector m_vertexWasRendered; }; DepthBoundsRangeUnrestrictedTestInstance::DepthBoundsRangeUnrestrictedTestInstance (Context& context, const DepthRangeUnrestrictedParam param) : DepthRangeUnrestrictedTestInstance(context, param) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); // Create render pass for second draw, we keep the first draw's contents of the depth buffer. m_renderPassSecondDraw = makeRenderPass(vk, vkDevice, m_colorFormat, m_param.depthFormat, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_LOAD); // Create framebuffer for second draw. { VkImageView attachmentBindInfos[2] = { *m_colorAttachmentView, *m_depthAttachmentView, }; const VkFramebufferCreateInfo framebufferParams = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkFramebufferCreateFlags flags; *m_renderPassSecondDraw, // VkRenderPass renderPass; 2u, // deUint32 attachmentCount; attachmentBindInfos, // const VkImageView* pAttachments; (deUint32)m_renderSize.x(), // deUint32 width; (deUint32)m_renderSize.y(), // deUint32 height; 1u, // deUint32 layers; }; m_framebufferSecondDraw = createFramebuffer(vk, vkDevice, &framebufferParams); } // Create pipeline m_pipelineSecondDraw = buildPipeline(*m_renderPassSecondDraw); } DepthBoundsRangeUnrestrictedTestInstance::~DepthBoundsRangeUnrestrictedTestInstance (void) { } tcu::TestStatus DepthBoundsRangeUnrestrictedTestInstance::iterate (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); // This test will draw the same scene two times. // First one will render the points depending on if the pass the depth test and if clear depth value passes the // depthBounds test. // // The second one, will render the same scene but the the point positions will have depth buffer values from // the first draw. If they pass the depth test, the depthBounds test will check the content of the depth buffer, // which is most cases, will make that the second result differs from the first one, hence the need to split // the verification in two steps. prepareCommandBuffer(true); submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); tcu::TestStatus status = verifyTestResult(true); if (status.getCode() != QP_TEST_RESULT_PASS) return status; prepareCommandBuffer(false); submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); return verifyTestResult(false); } void DepthBoundsRangeUnrestrictedTestInstance::prepareCommandBuffer (bool firstDraw) { const DeviceInterface& vk = m_context.getDeviceInterface(); if (!firstDraw) { vk.resetCommandBuffer(*m_cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); // Color image layout changed after verifying the first draw call, restore it. m_imageLayoutBarriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; m_imageLayoutBarriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; // Depth image layout changed after verifying the first draw call, restore it. m_imageLayoutBarriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; m_imageLayoutBarriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; } beginCommandBuffer(vk, *m_cmdBuffer, 0u); vk.cmdPipelineBarrier(*m_cmdBuffer, (firstDraw ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(m_imageLayoutBarriers), m_imageLayoutBarriers); prepareRenderPass((firstDraw ? *m_renderPass : *m_renderPassSecondDraw), (firstDraw ? *m_framebuffer : *m_framebufferSecondDraw), (firstDraw ? *m_pipeline : *m_pipelineSecondDraw)); endCommandBuffer(vk, *m_cmdBuffer); } tcu::TestStatus DepthBoundsRangeUnrestrictedTestInstance::verifyTestResult (bool firstDraw) { deBool compareOk = DE_TRUE; const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); tcu::TestLog& log = m_context.getTestContext().getLog(); Allocator& allocator = m_context.getDefaultAllocator(); tcu::TextureLevel refImage (vk::mapVkFormat(m_colorFormat), 32, 32); float clearValue = m_param.depthBufferClearValue.depthStencil.depth; double epsilon = 1e-5; // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) clearValue = de::min(de::max(clearValue, 0.0f), 1.0f); // Generate reference image { VkClearValue clearColor = defaultClearValue(m_colorFormat); tcu::Vec4 clearColorVec4 (clearColor.color.float32[0], clearColor.color.float32[1], clearColor.color.float32[2], clearColor.color.float32[3]); tcu::clear(refImage.getAccess(), clearColorVec4); for (std::vector::const_iterator vertex = m_vertices.begin(); vertex != m_vertices.end(); ++vertex) { // Depth Clamp is enabled, then we clamp point depth to viewport's maxDepth and minDepth values and later check if it is inside depthBounds volume. float scaling = ((vertex->position.z() / vertex->position.w()) * (m_param.viewportMaxDepth - m_param.viewportMinDepth)) + m_param.viewportMinDepth; float depth = de::min(de::max(scaling, m_param.viewportMinDepth), m_param.viewportMaxDepth); if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) depth = de::min(de::max(depth, 0.0f), 1.0f); auto i = vertex - m_vertices.begin(); // Depending if the first draw call succeed, we need to know if the second draw call will render the points because the depth buffer content // will determine if it passes the depth test and the depth bounds test. bool firstDrawHasPassedDepthBoundsTest = !firstDraw && m_vertexWasRendered[i]; float depthBufferValue = firstDrawHasPassedDepthBoundsTest ? depth : clearValue; // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) depthBufferValue = de::min(de::max(depthBufferValue, 0.0f), 1.0f); // Check that the point passes the depth test and the depth bounds test. if (compareDepthResult(m_param.depthCompareOp, depth, depthBufferValue) && depthBufferValue >= m_param.minDepthBounds && depthBufferValue <= m_param.maxDepthBounds) { deInt32 x = static_cast((((vertex->position.x() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.x() - 1)); deInt32 y = static_cast((((vertex->position.y() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.y() - 1)); refImage.getAccess().setPixel(vertex->color, x, y); if (firstDraw) m_vertexWasRendered.push_back(true); continue; } if (firstDraw) m_vertexWasRendered.push_back(false); } } // Check the rendered image { de::MovePtr result = vkt::pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize); std::string description = "Image comparison draw "; description += (firstDraw ? "1" : "2"); compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(), "IntImageCompare", description.c_str(), refImage.getAccess(), result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT); if (!compareOk) return tcu::TestStatus::fail("Image mismatch"); } // Check depth buffer contents { de::MovePtr depthResult = readDepthAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_depthImage, m_param.depthFormat, m_renderSize); log << tcu::TestLog::Message; for (std::vector::const_iterator vertex = m_vertices.begin(); vertex != m_vertices.end(); ++vertex) { deInt32 x = static_cast((((vertex->position.x() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.x() - 1)); deInt32 y = static_cast((((vertex->position.y() / vertex->position.w()) + 1.0f) / 2.0f) * static_cast(m_renderSize.y() - 1)); tcu::Vec4 depth = depthResult->getAccess().getPixel(x, y); // Check depth values are valid if (depth.y() != 0.0f || depth.z() != 0.0f || depth.w() != 1.0f) { log << tcu::TestLog::Message << "Draw " << (firstDraw ? "1" : "2") << ": Invalid depth buffer values for pixel (" << x << ", " << y << ") = (" << depth.x() << ", " << depth.y() << ", " << depth.z() << ", " << depth.w() << "." << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } // Depth Clamp is enabled, so we clamp point depth to viewport's maxDepth and minDepth values, or 0.0f and 1.0f is format is not float. float scaling = (vertex->position.z() / vertex->position.w()) * (m_param.viewportMaxDepth - m_param.viewportMinDepth) + m_param.viewportMinDepth; float expectedDepth = de::min(de::max(scaling, m_param.viewportMinDepth), m_param.viewportMaxDepth); auto i = vertex - m_vertices.begin(); // Depending if the first draw call succeed, we need to know if the second draw call will render the points because the depth buffer content // will determine if it passes the depth test and the depth bounds test. bool firstDrawHasPassedDepthBoundsTest = !firstDraw && m_vertexWasRendered[i]; // If we are in the first draw call, the depth buffer content is clearValue. If we are in the second draw call, it is going to be depth.x() if the first // succeeded. float depthBufferValue = firstDrawHasPassedDepthBoundsTest ? depth.x() : clearValue; // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) depthBufferValue = de::min(de::max(depthBufferValue, 0.0f), 1.0f); // Calculate the expectd depth depending on the depth test and the depth bounds test results. expectedDepth = (compareDepthResult(m_param.depthCompareOp, expectedDepth, depthBufferValue) && depthBufferValue <= m_param.maxDepthBounds && depthBufferValue >= m_param.minDepthBounds) ? expectedDepth : depthBufferValue; // For non-float depth formats, depth value is clampled to the range [0, 1]. if (isFloatingPointDepthFormat(m_param.depthFormat) == VK_FALSE) expectedDepth = de::min(de::max(expectedDepth, 0.0f), 1.0f); if (fabs(expectedDepth - depth.x()) > epsilon) { log << tcu::TestLog::Message << "Draw " << (firstDraw ? "1" : "2") << ": Error pixel (" << x << ", " << y << "). Depth value " << depth.x() << ", expected " << expectedDepth << ", error " << fabs(expectedDepth - depth.x()) << tcu::TestLog::EndMessage; compareOk = DE_FALSE; } } if (!compareOk) return tcu::TestStatus::fail("Depth buffer mismatch"); } return tcu::TestStatus::pass("Result images matches references"); } class DepthRangeUnrestrictedTest : public vkt::TestCase { public: DepthRangeUnrestrictedTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, const DepthRangeUnrestrictedParam param) : vkt::TestCase (testContext, name, description) , m_param (param) { } virtual ~DepthRangeUnrestrictedTest (void) { } virtual void initPrograms (SourceCollections& programCollection) const; virtual TestInstance* createInstance (Context& context) const; protected: const DepthRangeUnrestrictedParam m_param; }; void DepthRangeUnrestrictedTest::initPrograms (SourceCollections& programCollection) const { programCollection.glslSources.add("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" " gl_PointSize = 1.0f;\n" " vtxColor = color;\n" "}\n"); programCollection.glslSources.add("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"); } TestInstance* DepthRangeUnrestrictedTest::createInstance (Context& context) const { if (m_param.depthBoundsTestEnable) return new DepthBoundsRangeUnrestrictedTestInstance(context, m_param); return new DepthRangeUnrestrictedTestInstance(context, m_param); } } // anonymous tcu::TestCaseGroup* createDepthRangeUnrestrictedTests (tcu::TestContext& testCtx) { de::MovePtr depthTests (new tcu::TestCaseGroup(testCtx, "depth_range_unrestricted", "VK_EXT_depth_range_unrestricted tests")); const VkFormat depthFormats[] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM, }; const VkCompareOp compareOps[] = { VK_COMPARE_OP_GREATER, VK_COMPARE_OP_GREATER_OR_EQUAL, VK_COMPARE_OP_LESS, VK_COMPARE_OP_LESS_OR_EQUAL, }; float viewportValues[] = {2.0f, 6.0f, 12.0f}; float depthBoundsValues[] = {2.0f, 4.0f, 8.0f}; float wcValues[] = {2.0f, 6.0f, 12.0f}; float clearValues[] = {2.0f, -3.0f, 6.0f, -7.0f}; // Depth clear values outside range [0.0f, 1.0f]. { de::MovePtr depthClearValueTests (new tcu::TestCaseGroup(testCtx, "clear_value", "Depth Clear value unrestricted")); DepthRangeUnrestrictedParam testParams; testParams.testClearValueOnly = VK_TRUE; testParams.depthClampEnable = VK_FALSE; testParams.wc = 1.0f; testParams.viewportMinDepth = 0.0f; testParams.viewportMaxDepth = 1.0f; testParams.minDepthBounds = 0.0f; testParams.maxDepthBounds = 1.0f; testParams.depthBoundsTestEnable = VK_FALSE; testParams.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DEPTH_BOUNDS_STATIC; for (int format = 0; format < DE_LENGTH_OF_ARRAY(depthFormats); ++format) { testParams.depthFormat = depthFormats[format]; testParams.depthBufferClearValue = defaultClearValue(depthFormats[format]); for (int val = 0; val < DE_LENGTH_OF_ARRAY(clearValues); val++) { testParams.depthBufferClearValue.depthStencil.depth = clearValues[val]; depthClearValueTests->addChild(newTestCase(testCtx, testParams)); } } depthTests->addChild(depthClearValueTests.release()); } // Viewport's depth unrestricted range { de::MovePtr viewportTests (new tcu::TestCaseGroup(testCtx, "viewport", "Viewport depth unrestricted range")); DepthRangeUnrestrictedParam testParams; testParams.testClearValueOnly = VK_FALSE; testParams.wc = 1.0f; testParams.depthClampEnable = VK_TRUE; testParams.minDepthBounds = 0.0f; testParams.maxDepthBounds = 1.0f; testParams.depthBoundsTestEnable = VK_FALSE; for (int format = 0; format < DE_LENGTH_OF_ARRAY(depthFormats); ++format) { testParams.depthFormat = depthFormats[format]; testParams.depthBufferClearValue = defaultClearValue(testParams.depthFormat); for (int compareOp = 0; compareOp < DE_LENGTH_OF_ARRAY(compareOps); compareOp++) { testParams.depthCompareOp = compareOps[compareOp]; for (int clearValue = 0; clearValue < DE_LENGTH_OF_ARRAY(clearValues); clearValue++) { testParams.depthBufferClearValue.depthStencil.depth = clearValues[clearValue]; for (int viewportValue = 0; viewportValue < DE_LENGTH_OF_ARRAY(viewportValues); viewportValue++) { testParams.viewportMinDepth = -viewportValues[viewportValue]; testParams.viewportMaxDepth = viewportValues[viewportValue]; testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DEPTH_BOUNDS_STATIC; viewportTests->addChild(newTestCase(testCtx, testParams)); testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DYNAMIC; viewportTests->addChild(newTestCase(testCtx, testParams)); } } } } depthTests->addChild(viewportTests.release()); } // DepthBounds's depth unrestricted range { de::MovePtr depthBoundsTests (new tcu::TestCaseGroup(testCtx, "depthbounds", "Depthbounds unrestricted range")); DepthRangeUnrestrictedParam testParams; testParams.testClearValueOnly = VK_FALSE; testParams.wc = 1.0f; testParams.depthClampEnable = VK_TRUE; testParams.depthBoundsTestEnable = VK_TRUE; for (int format = 0; format < DE_LENGTH_OF_ARRAY(depthFormats); ++format) { testParams.depthFormat = depthFormats[format]; testParams.depthBufferClearValue = defaultClearValue(testParams.depthFormat); for (int compareOp = 0; compareOp < DE_LENGTH_OF_ARRAY(compareOps); compareOp++) { testParams.depthCompareOp = compareOps[compareOp]; for (int clearValue = 0; clearValue < DE_LENGTH_OF_ARRAY(clearValues); clearValue++) { testParams.depthBufferClearValue.depthStencil.depth = clearValues[clearValue]; for (int viewportValue = 0; viewportValue < DE_LENGTH_OF_ARRAY(viewportValues); viewportValue++) { testParams.viewportMinDepth = -viewportValues[viewportValue]; testParams.viewportMaxDepth = viewportValues[viewportValue]; for (int depthValue = 0; depthValue < DE_LENGTH_OF_ARRAY(depthBoundsValues); depthValue++) { testParams.minDepthBounds = -depthBoundsValues[depthValue]; testParams.maxDepthBounds = depthBoundsValues[depthValue]; testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DEPTH_BOUNDS_STATIC; depthBoundsTests->addChild(newTestCase(testCtx, testParams)); testParams.viewportDepthBoundsMode = TEST_MODE_DEPTH_BOUNDS_DYNAMIC; depthBoundsTests->addChild(newTestCase(testCtx, testParams)); testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DEPTH_BOUNDS_DYNAMIC; depthBoundsTests->addChild(newTestCase(testCtx, testParams)); } } } } } depthTests->addChild(depthBoundsTests.release()); } // Depth clamping disabled { de::MovePtr noDepthClampingTests (new tcu::TestCaseGroup(testCtx, "depthclampingdisabled", "Depth clamping disabled tests")); DepthRangeUnrestrictedParam testParams; testParams.testClearValueOnly = VK_FALSE; testParams.depthClampEnable = VK_FALSE; testParams.minDepthBounds = 0.0f; testParams.maxDepthBounds = 1.0f; testParams.depthBoundsTestEnable = VK_FALSE; testParams.viewportDepthBoundsMode = TEST_MODE_VIEWPORT_DEPTH_BOUNDS_STATIC; for (int format = 0; format < DE_LENGTH_OF_ARRAY(depthFormats); ++format) { testParams.depthFormat = depthFormats[format]; testParams.depthBufferClearValue = defaultClearValue(testParams.depthFormat); for (int compareOp = 0; compareOp < DE_LENGTH_OF_ARRAY(compareOps); compareOp++) { testParams.depthCompareOp = compareOps[compareOp]; for (int clearValue = 0; clearValue < DE_LENGTH_OF_ARRAY(clearValues); clearValue++) { testParams.depthBufferClearValue.depthStencil.depth = clearValues[clearValue]; for (int viewportValue = 0; viewportValue < DE_LENGTH_OF_ARRAY(viewportValues); viewportValue++) { testParams.viewportMinDepth = -viewportValues[viewportValue]; testParams.viewportMaxDepth = viewportValues[viewportValue]; for (int wc = 0; wc < DE_LENGTH_OF_ARRAY(wcValues); wc++) { testParams.wc = wcValues[wc]; noDepthClampingTests->addChild(newTestCase(testCtx, testParams)); } } } } } depthTests->addChild(noDepthClampingTests.release()); } return depthTests.release(); } } // pipeline } // vkt