blob: 3fc330ad0318b5962f171215b4dfce5fef85bcde [file] [log] [blame]
/*------------------------------------------------------------------------
* 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;
};
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);
}
// Render pass
{
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);
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);
}
// Framebuffer
{
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);
std::vector<VkImageView> fbAttachments(2);
fbAttachments[0] = *m_colorTargetView;
fbAttachments[1] = *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));
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();
// 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 VkClearColorValue clearColor = makeClearValueColor(kClearColor).color;
const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
const VkClearDepthStencilValue clearDepth = makeClearValueDepthStencil(kClearDepth, 0u).depthStencil;
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, 1, &subresourceRange);
vk.cmdClearDepthStencilImage(*cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearDepth, 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);
}
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);
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");
}
virtual TestInstance* createInstance (Context& context) const
{
return new InvertedDepthRangesTestInstance(context, m_params);
}
private:
const TestParams m_params;
};
void populateTestGroup (tcu::TestCaseGroup* testGroup)
{
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,
};
std::string name = cDepthClamp.name + "_" + cDepthParams.name;
testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name, "", params));
}
}
} // anonymous
tcu::TestCaseGroup* createInvertedDepthRangesTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "inverted_depth_ranges", "Inverted depth ranges", populateTestGroup);
}
} // Draw
} // vkt