| /*------------------------------------------------------------------------ |
| * 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 "vkCmdUtil.hpp" |
| |
| #include "tcuVector.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "deSharedPtr.hpp" |
| |
| #include <utility> |
| #include <array> |
| #include <vector> |
| #include <iterator> |
| |
| 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; |
| VkBool32 useDynamicRendering; |
| }; |
| |
| 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<Vec4, 3u> 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<tcu::ConstPixelBufferAccess, tcu::ConstPixelBufferAccess>; |
| |
| InvertedDepthRangesTestInstance (Context& context, const TestParams& params); |
| tcu::TestStatus iterate (void); |
| ColorAndDepth draw (const VkViewport viewport); |
| MovePtr<tcu::TextureLevel> generateReferenceImage (ReferenceImageType refType) const; |
| |
| private: |
| const TestParams m_params; |
| const VkFormat m_colorAttachmentFormat; |
| const VkFormat m_depthAttachmentFormat; |
| SharedPtr<Image> m_colorTargetImage; |
| Move<VkImageView> m_colorTargetView; |
| SharedPtr<Image> m_depthTargetImage; |
| Move<VkImageView> m_depthTargetView; |
| SharedPtr<Buffer> m_vertexBuffer; |
| Move<VkRenderPass> m_renderPass; |
| Move<VkFramebuffer> m_framebuffer; |
| Move<VkPipelineLayout> m_pipelineLayout; |
| Move<VkPipeline> 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<VkDeviceSize>(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<size_t>(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.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<VkImageView> 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<VkDynamicState> dynamicStates; |
| dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT); |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0)); |
| const Unique<VkShaderModule> 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<VkViewport>(), std::vector<VkRect2D>(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)); |
| |
| VkPipelineRenderingCreateInfoKHR renderingCreateInfo |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, |
| DE_NULL, |
| 0u, |
| 1u, |
| &m_colorAttachmentFormat, |
| m_depthAttachmentFormat, |
| m_depthAttachmentFormat |
| }; |
| |
| if (m_params.useDynamicRendering) |
| pipelineCreateInfo.pNext = &renderingCreateInfo; |
| |
| m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo); |
| } |
| |
| InvertedDepthRangesTestInstance::ColorAndDepth InvertedDepthRangesTestInstance::draw (const VkViewport viewport) |
| { |
| 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<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| // Draw |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport); |
| |
| { |
| 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); |
| } |
| |
| if (m_params.useDynamicRendering) |
| beginRendering(vk, *cmdBuffer, *m_colorTargetView, *m_depthTargetView, false, makeRect2D(kImageExtent), clearColor, clearDepth); |
| else |
| beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(kImageExtent)); |
| |
| { |
| const VkDeviceSize offset = 0; |
| const VkBuffer buffer = m_vertexBuffer->object(); |
| |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset); |
| } |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); |
| vk.cmdDraw(*cmdBuffer, 3, 1, 0, 0); |
| |
| if (m_params.useDynamicRendering) |
| endRendering(vk, *cmdBuffer); |
| else |
| 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<int>(kImageExtent.width); |
| const auto iHeight = static_cast<int>(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); |
| |
| return ColorAndDepth(colorPixels, depthPixels); |
| } |
| } |
| |
| MovePtr<tcu::TextureLevel> InvertedDepthRangesTestInstance::generateReferenceImage (ReferenceImageType refType) const |
| { |
| const auto iWidth = static_cast<int>(kImageExtent.width); |
| const auto iHeight = static_cast<int>(kImageExtent.height); |
| const bool color = (refType == ReferenceImageType::COLOR); |
| const auto tcuFormat = mapVkFormat(color ? m_colorAttachmentFormat : VK_FORMAT_D16_UNORM_S8_UINT); |
| MovePtr<tcu::TextureLevel> image (new tcu::TextureLevel(tcuFormat, iWidth, iHeight)); |
| const tcu::PixelBufferAccess access (image->getAccess()); |
| const float fImageDim = static_cast<float>(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<float, 3> 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<float>(x) + 0.5f; |
| const float ycoord = static_cast<float>(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; |
| } |
| |
| tcu::TestStatus InvertedDepthRangesTestInstance::iterate (void) |
| { |
| // Set up the viewport and draw |
| |
| const VkViewport viewport = |
| { |
| 0.0f, // float x; |
| 0.0f, // float y; |
| static_cast<float>(kImageExtent.width), // float width; |
| static_cast<float>(kImageExtent.height), // float height; |
| m_params.minDepth, // float minDepth; |
| m_params.maxDepth, // float maxDepth; |
| }; |
| |
| ColorAndDepth results = draw(viewport); |
| 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.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, bool useDynamicRendering) |
| { |
| 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, |
| useDynamicRendering |
| }; |
| |
| std::string name = cDepthClamp.name + "_" + cDepthParams.name; |
| testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name, "", params)); |
| } |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createInvertedDepthRangesTests (tcu::TestContext& testCtx, bool useDynamicRendering) |
| { |
| return createTestGroup(testCtx, "inverted_depth_ranges", "Inverted depth ranges", populateTestGroup, useDynamicRendering); |
| } |
| |
| } // Draw |
| } // vkt |