/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 The Khronos Group Inc. * Copyright (c) 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Inverted depth ranges tests. *//*--------------------------------------------------------------------*/ #include "vktDrawInvertedDepthRangesTests.hpp" #include "vktDrawCreateInfoUtil.hpp" #include "vktDrawImageObjectUtil.hpp" #include "vktDrawBufferObjectUtil.hpp" #include "vktTestGroupUtil.hpp" #include "vktTestCaseUtil.hpp" #include "vkPrograms.hpp" #include "vkTypeUtil.hpp" #include "vkImageUtil.hpp" #include "vkQueryUtil.hpp" #include "vkCmdUtil.hpp" #include "tcuVector.hpp" #include "tcuTextureUtil.hpp" #include "tcuImageCompare.hpp" #include "tcuTestLog.hpp" #include "deSharedPtr.hpp" #include #include #include #include namespace vkt { namespace Draw { namespace { using namespace vk; using tcu::Vec4; using de::SharedPtr; using de::MovePtr; struct TestParams { float minDepth; float maxDepth; VkBool32 depthClampEnable; VkBool32 depthBiasEnable; float depthBiasClamp; const SharedGroupParams groupParams; }; constexpr deUint32 kImageDim = 256u; const VkExtent3D kImageExtent = makeExtent3D(kImageDim, kImageDim, 1u); const Vec4 kClearColor (0.0f, 0.0f, 0.0f, 1.0f); constexpr float kClearDepth = 1.0f; constexpr int kClearStencil = 0; constexpr int kMaskedStencil = 1; constexpr float kDepthEpsilon = 0.00025f; // Used to decide if a calculated depth passes the depth test. constexpr float kDepthThreshold = 0.0025f; // Used when checking depth buffer values. Less than depth delta in each pixel (~= 1.4/205). constexpr float kMargin = 0.2f; // Space between triangle and image border. See kVertices. constexpr float kDiagonalMargin = 0.00125f; // Makes sure the image diagonal falls inside the triangle. See kVertices. const Vec4 kVertexColor (0.0f, 0.5f, 0.5f, 1.0f); // Note: the first component will vary. // Maximum depth slope is constant for triangle and the value here is true only for triangle used it this tests. constexpr float kMaxDepthSlope = 1.4f / 205; const std::array kVertices = {{ Vec4(-1.0f + kMargin, -1.0f + kMargin, -0.2f, 1.0f), // 0-----2 Vec4(-1.0f + kMargin, 1.0f - kMargin + kDiagonalMargin, 0.0f, 1.0f), // | / Vec4( 1.0f - kMargin + kDiagonalMargin, -1.0f + kMargin, 1.2f, 1.0f), // 1|/ }}; class InvertedDepthRangesTestInstance : public TestInstance { public: enum class ReferenceImageType { COLOR = 0, DEPTH, }; using ColorAndDepth = std::pair; InvertedDepthRangesTestInstance (Context& context, const TestParams& params); tcu::TestStatus iterate (void); void preRenderCommands (VkCommandBuffer cmdBuffer, const VkClearValue& clearColor, const VkClearValue& clearDepth); void draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport); MovePtr generateReferenceImage (ReferenceImageType refType) const; #ifndef CTS_USES_VULKANSC void beginSecondaryCmdBuffer (VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u); void beginRender (VkCommandBuffer cmdBuffer, const VkClearValue& clearColor, const VkClearValue& clearDepth, VkRenderingFlagsKHR renderingFlags = 0); #endif // CTS_USES_VULKANSC private: const TestParams m_params; const VkFormat m_colorAttachmentFormat; const VkFormat m_depthAttachmentFormat; SharedPtr m_colorTargetImage; Move m_colorTargetView; SharedPtr m_depthTargetImage; Move m_depthTargetView; SharedPtr m_vertexBuffer; Move m_renderPass; Move m_framebuffer; Move m_pipelineLayout; Move m_pipeline; }; InvertedDepthRangesTestInstance::InvertedDepthRangesTestInstance (Context& context, const TestParams& params) : TestInstance (context) , m_params (params) , m_colorAttachmentFormat (VK_FORMAT_R8G8B8A8_UNORM) , m_depthAttachmentFormat (VK_FORMAT_D16_UNORM) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); auto& alloc = m_context.getDefaultAllocator(); auto qIndex = m_context.getUniversalQueueFamilyIndex(); // Vertex data { const auto dataSize = static_cast(kVertices.size() * sizeof(decltype(kVertices)::value_type)); m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), alloc, MemoryRequirement::HostVisible); deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), kVertices.data(), static_cast(dataSize)); flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE); } const VkImageUsageFlags targetImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; const VkImageUsageFlags depthTargeUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; const ImageCreateInfo targetImageCreateInfo( VK_IMAGE_TYPE_2D, // imageType, m_colorAttachmentFormat, // format, kImageExtent, // extent, 1u, // mipLevels, 1u, // arrayLayers, VK_SAMPLE_COUNT_1_BIT, // samples, VK_IMAGE_TILING_OPTIMAL, // tiling, targetImageUsageFlags); // usage, m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, alloc, qIndex); const ImageCreateInfo depthTargetImageCreateInfo( VK_IMAGE_TYPE_2D, // imageType, m_depthAttachmentFormat, // format, kImageExtent, // extent, 1u, // mipLevels, 1u, // arrayLayers, VK_SAMPLE_COUNT_1_BIT, // samples, VK_IMAGE_TILING_OPTIMAL, // tiling, depthTargeUsageFlags); // usage, m_depthTargetImage = Image::createAndAlloc(vk, device, depthTargetImageCreateInfo, alloc, qIndex); const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat); m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo); const ImageViewCreateInfo depthTargetViewInfo(m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_depthAttachmentFormat); m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo); // Render pass and framebuffer if (!m_params.groupParams->useDynamicRendering) { RenderPassCreateInfo renderPassCreateInfo; renderPassCreateInfo.addAttachment(AttachmentDescription( m_colorAttachmentFormat, // format VK_SAMPLE_COUNT_1_BIT, // samples VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp VK_ATTACHMENT_STORE_OP_STORE, // storeOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp VK_IMAGE_LAYOUT_GENERAL, // initialLayout VK_IMAGE_LAYOUT_GENERAL)); // finalLayout renderPassCreateInfo.addAttachment(AttachmentDescription( m_depthAttachmentFormat, // format VK_SAMPLE_COUNT_1_BIT, // samples VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp VK_ATTACHMENT_STORE_OP_STORE, // storeOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp VK_IMAGE_LAYOUT_GENERAL, // initialLayout VK_IMAGE_LAYOUT_GENERAL)); // finalLayout const VkAttachmentReference colorAttachmentReference = { 0u, VK_IMAGE_LAYOUT_GENERAL }; const VkAttachmentReference depthAttachmentReference = { 1u, VK_IMAGE_LAYOUT_GENERAL }; renderPassCreateInfo.addSubpass(SubpassDescription( VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint (VkSubpassDescriptionFlags)0, // flags 0u, // inputAttachmentCount DE_NULL, // inputAttachments 1u, // colorAttachmentCount &colorAttachmentReference, // colorAttachments DE_NULL, // resolveAttachments depthAttachmentReference, // depthStencilAttachment 0u, // preserveAttachmentCount DE_NULL)); // preserveAttachments m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo); std::vector fbAttachments { *m_colorTargetView, *m_depthTargetView }; const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, fbAttachments, kImageExtent.width, kImageExtent.height, 1u); m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo); } // Vertex input const VkVertexInputBindingDescription vertexInputBindingDescription = { 0u, // uint32_t binding; sizeof(Vec4), // uint32_t stride; VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; }; const VkVertexInputAttributeDescription vertexInputAttributeDescription = { 0u, // uint32_t location; 0u, // uint32_t binding; VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; 0u // uint32_t offset; }; const PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 1, &vertexInputAttributeDescription); // Graphics pipeline const auto scissor = makeRect2D(kImageExtent); std::vector dynamicStates; dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT); const Unique vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0)); const Unique fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0)); const PipelineLayoutCreateInfo pipelineLayoutCreateInfo; m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo); const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState; PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0); pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT)); pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT)); pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState)); pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)); pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState (1, &colorBlendAttachmentState)); pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (1, std::vector(), std::vector(1, scissor))); pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState (true, true)); pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState ( m_params.depthClampEnable, // depthClampEnable VK_FALSE, // rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // polygonMode VK_CULL_MODE_NONE, // cullMode VK_FRONT_FACE_CLOCKWISE, // frontFace m_params.depthBiasEnable, // depthBiasEnable 0.0f, // depthBiasConstantFactor m_params.depthBiasEnable ? m_params.depthBiasClamp : 0.0f, // depthBiasClamp m_params.depthBiasEnable ? 1.0f : 0.0f, // depthBiasSlopeFactor 1.0f)); // lineWidth pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ()); pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState (dynamicStates)); #ifndef CTS_USES_VULKANSC VkPipelineRenderingCreateInfoKHR renderingCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, DE_NULL, 0u, 1u, &m_colorAttachmentFormat, m_depthAttachmentFormat, VK_FORMAT_UNDEFINED }; if (m_params.groupParams->useDynamicRendering) pipelineCreateInfo.pNext = &renderingCreateInfo; #endif // CTS_USES_VULKANSC m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo); } void InvertedDepthRangesTestInstance::preRenderCommands (VkCommandBuffer cmdBuffer, const VkClearValue& clearColor, const VkClearValue& clearDepth) { const DeviceInterface& vk = m_context.getDeviceInterface(); const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT); const ImageSubresourceRange depthSubresourceRange (VK_IMAGE_ASPECT_DEPTH_BIT); initialTransitionColor2DImage(vk, cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); initialTransitionDepth2DImage(vk, cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); vk.cmdClearColorImage(cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange); vk.cmdClearDepthStencilImage(cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearDepth.depthStencil, 1u, &depthSubresourceRange); const VkMemoryBarrier memBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask; }; const VkMemoryBarrier depthBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask; }; vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL); vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), 0, 1, &depthBarrier, 0, DE_NULL, 0, DE_NULL); } void InvertedDepthRangesTestInstance::draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkBuffer buffer = m_vertexBuffer->object(); const VkDeviceSize offset = 0; vk.cmdSetViewport(cmdBuffer, 0u, 1u, &viewport); vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &buffer, &offset); vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); vk.cmdDraw(cmdBuffer, 3, 1, 0, 0); } MovePtr InvertedDepthRangesTestInstance::generateReferenceImage (ReferenceImageType refType) const { const auto iWidth = static_cast(kImageExtent.width); const auto iHeight = static_cast(kImageExtent.height); const bool color = (refType == ReferenceImageType::COLOR); const auto tcuFormat = mapVkFormat(color ? m_colorAttachmentFormat : VK_FORMAT_D16_UNORM_S8_UINT); MovePtr image (new tcu::TextureLevel(tcuFormat, iWidth, iHeight)); const tcu::PixelBufferAccess access (image->getAccess()); const float fImageDim = static_cast(kImageDim); const float p1f = fImageDim * kMargin / 2.0f; const float p2f = fImageDim * (2.0f - kMargin + kDiagonalMargin) / 2.0f; const float triangleSide = fImageDim * (2.0f - (2.0f*kMargin - kDiagonalMargin)) / 2.0f; const float clampMin = de::min(m_params.minDepth, m_params.maxDepth); const float clampMax = de::max(m_params.minDepth, m_params.maxDepth); std::array depthValues; float depthBias = 0.0f; // Depth value of each vertex in kVertices. DE_ASSERT(depthValues.size() == kVertices.size()); std::transform(begin(kVertices), end(kVertices), begin(depthValues), [](const Vec4& coord) { return coord.z(); }); if (color) tcu::clear(access, kClearColor); else { tcu::clearDepth(access, kClearDepth); tcu::clearStencil(access, kClearStencil); if (m_params.depthBiasEnable) { const float depthBiasSlopeFactor = 1.0f; const float r = 0.000030518f; // minimum resolvable difference is an implementation-dependent parameter const float depthBiasConstantFactor = 0.0f; // so we use factor 0.0 to not include it; same as in PipelineCreateInfo // Equations taken from vkCmdSetDepthBias manual page depthBias = kMaxDepthSlope * depthBiasSlopeFactor + r * depthBiasConstantFactor; // dbclamp(x) function depends on the sign of the depthBiasClamp if (m_params.depthBiasClamp < 0.0f) depthBias = de::max(depthBias, m_params.depthBiasClamp); else if (m_params.depthBiasClamp > 0.0f) depthBias = de::min(depthBias, m_params.depthBiasClamp); if (m_params.maxDepth < m_params.minDepth) depthBias *= -1.0f; } } for (int y = 0; y < iHeight; ++y) for (int x = 0; x < iWidth; ++x) { const float xcoord = static_cast(x) + 0.5f; const float ycoord = static_cast(y) + 0.5f; if (xcoord < p1f || xcoord > p2f) continue; if (ycoord < p1f || ycoord > p2f) continue; if (ycoord > -xcoord + fImageDim) continue; // Interpolate depth value taking the 3 triangle corners into account. const float b = (ycoord - p1f) / triangleSide; const float c = (xcoord - p1f) / triangleSide; const float a = 1.0f - b - c; const float depth = a * depthValues[0] + b * depthValues[1] + c * depthValues[2]; // Depth values are always limited to the range [0,1] by clamping after depth bias addition is performed const float depthClamped = de::clamp(depth + depthBias, 0.0f, 1.0f); const float depthFinal = depthClamped * m_params.maxDepth + (1.0f - depthClamped) * m_params.minDepth; const float storedDepth = (m_params.depthClampEnable ? de::clamp(depthFinal, clampMin, clampMax) : depthFinal); if (m_params.depthClampEnable || de::inRange(depth, -kDepthEpsilon, 1.0f + kDepthEpsilon)) { if (color) access.setPixel(Vec4(depthFinal, kVertexColor.y(), kVertexColor.z(), kVertexColor.w()), x, y); else { if (!m_params.depthClampEnable && (de::inRange(depth, -kDepthEpsilon, kDepthEpsilon) || de::inRange(depth, 1.0f - kDepthEpsilon, 1.0f + kDepthEpsilon))) { // We should avoid comparing this pixel due to possible rounding problems. // Pixels that should not be compared will be marked in the stencil aspect. access.setPixStencil(kMaskedStencil, x, y); } access.setPixDepth(storedDepth, x, y); } } } return image; } #ifndef CTS_USES_VULKANSC void InvertedDepthRangesTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags) { VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; renderingFlags, // VkRenderingFlagsKHR flags; 0u, // uint32_t viewMask; 1u, // uint32_t colorAttachmentCount; &m_colorAttachmentFormat, // const VkFormat* pColorAttachmentFormats; m_depthAttachmentFormat, // VkFormat depthAttachmentFormat; VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; }; const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo); VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; const VkCommandBufferBeginInfo commandBufBeginParams { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; usageFlags, // VkCommandBufferUsageFlags flags; &bufferInheritanceInfo }; const DeviceInterface& vk = m_context.getDeviceInterface(); VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams)); } void InvertedDepthRangesTestInstance::beginRender(VkCommandBuffer cmdBuffer, const VkClearValue& clearColor, const VkClearValue& clearDepth, VkRenderingFlagsKHR renderingFlags) { const DeviceInterface& vk = m_context.getDeviceInterface(); beginRendering(vk, cmdBuffer, *m_colorTargetView, *m_depthTargetView, false, makeRect2D(kImageExtent), clearColor, clearDepth, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, renderingFlags); } #endif // CTS_USES_VULKANSC tcu::TestStatus InvertedDepthRangesTestInstance::iterate (void) { // Set up the viewport and draw const VkViewport viewport { 0.0f, // float x; 0.0f, // float y; static_cast(kImageExtent.width), // float width; static_cast(kImageExtent.height), // float height; m_params.minDepth, // float minDepth; m_params.maxDepth, // float maxDepth; }; const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); auto& alloc = m_context.getDefaultAllocator(); const VkClearValue clearColor = makeClearValueColor(kClearColor); const VkClearValue clearDepth = makeClearValueDepthStencil(kClearDepth, 0u); // Command buffer const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex); const Unique cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo)); const Unique cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); Move secCmdBuffer; #ifndef CTS_USES_VULKANSC if (m_params.groupParams->useSecondaryCmdBuffer) { secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); // record secondary command buffer if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) { beginSecondaryCmdBuffer(*secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT); beginRender(*secCmdBuffer, clearColor, clearDepth); } else beginSecondaryCmdBuffer(*secCmdBuffer); draw(*secCmdBuffer, viewport); if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) endRendering(vk, *secCmdBuffer); endCommandBuffer(vk, *secCmdBuffer); // record primary command buffer beginCommandBuffer(vk, *cmdBuffer, 0u); preRenderCommands(*cmdBuffer, clearColor, clearDepth); if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) beginRender(*cmdBuffer, clearColor, clearDepth, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT); vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer); if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) endRendering(vk, *cmdBuffer); endCommandBuffer(vk, *cmdBuffer); } else if (m_params.groupParams->useDynamicRendering) { beginCommandBuffer(vk, *cmdBuffer); preRenderCommands(*cmdBuffer, clearColor, clearDepth); beginRender(*cmdBuffer, clearColor, clearDepth); draw(*cmdBuffer, viewport); endRendering(vk, *cmdBuffer); endCommandBuffer(vk, *cmdBuffer); } #endif // CTS_USES_VULKANSC if (!m_params.groupParams->useDynamicRendering) { beginCommandBuffer(vk, *cmdBuffer); preRenderCommands(*cmdBuffer, clearColor, clearDepth); beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(kImageExtent)); draw(*cmdBuffer, viewport); endRenderPass(vk, *cmdBuffer); endCommandBuffer(vk, *cmdBuffer); } // Submit submitCommandsAndWait(vk, device, queue, cmdBuffer.get()); // Get result const auto zeroOffset = makeOffset3D(0, 0, 0); const auto iWidth = static_cast(kImageExtent.width); const auto iHeight = static_cast(kImageExtent.height); const auto colorPixels = m_colorTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth, iHeight, VK_IMAGE_ASPECT_COLOR_BIT); const auto depthPixels = m_depthTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth, iHeight, VK_IMAGE_ASPECT_DEPTH_BIT); ColorAndDepth results (colorPixels, depthPixels); auto& resultImage = results.first; auto& resultDepth = results.second; // Verify results auto& log = m_context.getTestContext().getLog(); auto referenceImage = generateReferenceImage(ReferenceImageType::COLOR); auto referenceDepth = generateReferenceImage(ReferenceImageType::DEPTH); bool fail = false; // Color aspect. if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT)) fail = true; // Depth aspect. bool depthFail = false; const auto refWidth = referenceDepth->getWidth(); const auto refHeight = referenceDepth->getHeight(); const auto refAccess = referenceDepth->getAccess(); tcu::TextureLevel errorMask (mapVkFormat(VK_FORMAT_R8G8B8_UNORM), refWidth, refHeight); auto errorAccess = errorMask.getAccess(); const tcu::Vec4 kGreen (0.0f, 1.0f, 0.0f, 1.0f); const tcu::Vec4 kRed (1.0f, 0.0f, 0.0f, 1.0f); tcu::clear(errorAccess, kGreen); for (int y = 0; y < refHeight; ++y) for (int x = 0; x < refWidth; ++x) { // Ignore pixels that could be too close to having or not having coverage. const auto stencil = refAccess.getPixStencil(x, y); if (stencil == kMaskedStencil) continue; // Compare the rest using a known threshold. const auto refValue = refAccess.getPixDepth(x, y); const auto resValue = resultDepth.getPixDepth(x, y); if (!de::inRange(resValue, refValue - kDepthThreshold, refValue + kDepthThreshold)) { depthFail = true; errorAccess.setPixel(kRed, x, y); } } if (depthFail) { log << tcu::TestLog::Message << "Depth Image comparison failed" << tcu::TestLog::EndMessage; log << tcu::TestLog::Image("Result", "Result", resultDepth) << tcu::TestLog::Image("Reference", "Reference", refAccess) << tcu::TestLog::Image("ErrorMask", "Error mask", errorAccess); } if (fail || depthFail) return tcu::TestStatus::fail("Result images are incorrect"); return tcu::TestStatus::pass("Pass"); } class InvertedDepthRangesTest : public TestCase { public: InvertedDepthRangesTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params) : TestCase (testCtx, name, description) , m_params (params) { } void initPrograms (SourceCollections& programCollection) const { // Vertex shader { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "layout(location = 0) in highp vec4 in_position;\n" << "\n" << "out gl_PerVertex {\n" << " highp vec4 gl_Position;\n" << "};\n" << "\n" << "void main(void)\n" << "{\n" << " gl_Position = in_position;\n" << "}\n"; programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); } // Fragment shader { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "layout(location = 0) out highp vec4 out_color;\n" << "\n" << "void main(void)\n" << "{\n" << " out_color = vec4(gl_FragCoord.z, " << kVertexColor.y() << ", " << kVertexColor.z() << ", " << kVertexColor.w() << ");\n" << "}\n"; programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); } } virtual void checkSupport (Context& context) const { if (m_params.depthClampEnable) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_CLAMP); if (m_params.depthBiasEnable && m_params.depthBiasClamp != 0.0f) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_BIAS_CLAMP); if (m_params.minDepth > 1.0f || m_params.minDepth < 0.0f || m_params.maxDepth > 1.0f || m_params.maxDepth < 0.0f) context.requireDeviceFunctionality("VK_EXT_depth_range_unrestricted"); if (m_params.groupParams->useDynamicRendering) context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); } virtual TestInstance* createInstance (Context& context) const { return new InvertedDepthRangesTestInstance(context, m_params); } private: const TestParams m_params; }; void populateTestGroup (tcu::TestCaseGroup* testGroup, const SharedGroupParams groupParams) { const struct { std::string name; VkBool32 depthClamp; } depthClamp[] = { { "depthclamp", VK_TRUE }, { "nodepthclamp", VK_FALSE }, }; const struct { std::string name; float delta; VkBool32 depthBiasEnable; float depthBiasClamp; } depthParams[] = { { "deltazero", 0.0f, DE_FALSE, 0.0f }, { "deltasmall", 0.3f, DE_FALSE, 0.0f }, { "deltaone", 1.0f, DE_FALSE, 0.0f }, // depthBiasClamp must be smaller then maximum depth slope to make a difference { "deltaone_bias_clamp_neg", 1.0f, DE_TRUE, -0.003f }, { "deltasmall_bias_clamp_pos", 0.3f, DE_TRUE, 0.003f }, // Range > 1.0 requires VK_EXT_depth_range_unrestricted extension { "depth_range_unrestricted", 2.7f, DE_FALSE, 0.0f }, }; for (int ndxDepthClamp = 0; ndxDepthClamp < DE_LENGTH_OF_ARRAY(depthClamp); ++ndxDepthClamp) for (int ndxParams = 0; ndxParams < DE_LENGTH_OF_ARRAY(depthParams); ++ndxParams) { const auto& cDepthClamp = depthClamp[ndxDepthClamp]; const auto& cDepthParams = depthParams[ndxParams]; const float minDepth = 0.5f + cDepthParams.delta / 2.0f; const float maxDepth = minDepth - cDepthParams.delta; DE_ASSERT(minDepth >= maxDepth); const TestParams params { minDepth, maxDepth, cDepthClamp.depthClamp, cDepthParams.depthBiasEnable, cDepthParams.depthBiasClamp, groupParams }; std::string name = cDepthClamp.name + "_" + cDepthParams.name; testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name, "", params)); } } } // anonymous tcu::TestCaseGroup* createInvertedDepthRangesTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams) { return createTestGroup(testCtx, "inverted_depth_ranges", "Inverted depth ranges", populateTestGroup, groupParams); } } // Draw } // vkt