blob: fe893723b438dbf04b5269cf4432e73804291884 [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 Depth clamp tests.
*//*--------------------------------------------------------------------*/
#include "vkDefs.hpp"
#include "vktDrawDepthClampTests.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktDrawCreateInfoUtil.hpp"
#include "vktDrawBufferObjectUtil.hpp"
#include "vktDrawImageObjectUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuTestLog.hpp"
#include <cmath>
#include <limits>
#include "deMath.h"
namespace vkt
{
namespace Draw
{
namespace {
using namespace vk;
using namespace de;
using std::string;
using tcu::Vec4;
static const int WIDTH = 256;
static const int HEIGHT = 256;
struct ViewportData
{
float minDepth;
float maxDepth;
float depthValue;
float expectedValue;
};
struct TestParams
{
string testNameSuffix;
std::vector<ViewportData> viewportData;
bool enableDepthBias;
float depthBiasConstantFactor;
bool skipUNorm;
bool skipSNorm;
std::vector<const char*> requiredExtensions;
};
const VkFormat depthStencilImageFormatsToTest[] =
{
VK_FORMAT_D16_UNORM,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT
};
const float depthEpsilonValuesByFormat[] =
{
1e-5f,
std::numeric_limits<float>::epsilon(),
std::numeric_limits<float>::epsilon(),
1e-5f,
std::numeric_limits<float>::epsilon(),
std::numeric_limits<float>::epsilon()
};
const float initialClearDepth = 0.5f;
const TestParams depthClearValuesToTest[] =
{
{
"", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.0f, // maxDepth
0.3f, // depthValue
0.3f, // expectedValue
} },
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
false, // skipUNorm
false, // skipSNorm
{}, // requiredExtensions
},
{
"_clamp_input_negative", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.0f, // maxDepth
-1e6f, // depthValue
0.0f, // expectedValue
} },
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
false, // skipUNorm
false, // skipSNorm
{}, // requiredExtensions
},
{
"_clamp_input_positive", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.0f, // maxDepth
1.e6f, // depthValue
1.0f, // expectedValue
} },
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
false, // skipUNorm
false, // skipSNorm
{}, // requiredExtensions
},
{
"_depth_bias_clamp_input_negative", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.0f, // maxDepth
0.3f, // depthValue
0.0f, // expectedValue
} },
true, // enableDepthBias
-2e11f, // depthBiasConstantFactor
false, // skipUNorm
false, // skipSNorm
{}, // requiredExtensions
},
{
"_depth_bias_clamp_input_positive", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.0f, // maxDepth
0.7f, // depthValue
1.0f, // expectedValue
} },
true, // enableDepthBias
2e11f, // depthBiasConstantFactor
false, // skipUNorm
false, // skipSNorm
{}, // requiredExtensions
},
{
"_depth_range_unrestricted_negative", // testNameSuffix
{ { // viewportData
-1.5f, // minDepth
1.0f, // maxDepth
-1.5f, // depthValue
-1.5f, // expectedValue
} },
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
true, // skipUNorm
true, // skipSNorm
{
"VK_EXT_depth_range_unrestricted" // requiredExtensions[0]
},
},
{
"_depth_range_unrestricted_positive", // testNameSuffix
{ { // viewportData
0.0f, // minDepth
1.5f, // maxDepth
1.5f, // depthValue
1.5f, // expectedValue
} },
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
true, // skipUNorm
true, // skipSNorm
{
"VK_EXT_depth_range_unrestricted" // requiredExtensions[0]
},
},
{
"_clamp_four_viewports", // testNameSuffix
{ // viewportData
{
0.0f, // minDepth
0.5f, // maxDepth
0.7f, // depthValue
0.35f, // expectedValue: 0.7 * 0.5 + (1.0 - 0.7) * 0.0) = 0.35
},
{
0.9f, // minDepth
1.0f, // maxDepth
1.0f, // depthValue
1.0f, // expectedValue: 1.0 * 1.0 + (1.0 - 1.0) * 0.9 = 1.0
},
{
0.5f, // minDepth
1.0f, // maxDepth
0.9f, // depthValue
0.95f, // expectedValue: 0.9 * 1.0 + (1.0 - 0.9) * 0.5 = 0.95
},
{
0.5f, // minDepth
0.9f, // maxDepth
0.4f, // depthValue
0.66f, // expectedValue: 0.4 * 0.9 + (1.0 - 0.4) * 0.5 = 0.66
},
},
false, // enableDepthBias
0.0f, // depthBiasConstantFactor
true, // skipUNorm
true, // skipSNorm
{},
}
};
bool isUnormDepthFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D16_UNORM_S8_UINT:
/* Special case for combined depth-stencil-unorm modes for which tcu::getTextureChannelClass()
returns TEXTURECHANNELCLASS_LAST */
return true;
default:
return vk::isUnormFormat(format);
}
}
class DepthClampTestInstance : public TestInstance {
public:
DepthClampTestInstance (Context& context, const TestParams& params, const VkFormat format, const float epsilon);
tcu::TestStatus iterate ();
private:
tcu::ConstPixelBufferAccess draw ();
const TestParams m_params;
const VkFormat m_format;
const float m_epsilon;
std::vector<VkViewport> m_viewportVect;
std::vector<VkRect2D> m_scissorVect;
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;
};
static const Vec4 vertices[] = {
Vec4(-1.0f, -1.0f, 0.5f, 1.0f), // 0 -- 2
Vec4(-1.0f, 1.0f, 0.5f, 1.0f), // | / |
Vec4( 1.0f, -1.0f, 0.5f, 1.0f), // | / |
Vec4( 1.0f, 1.0f, 0.5f, 1.0f) // 1 -- 3
};
static const VkPrimitiveTopology verticesTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
DepthClampTestInstance::DepthClampTestInstance (Context& context, const TestParams& params, const VkFormat format, const float epsilon)
: TestInstance(context)
, m_params(params)
, m_format(format)
, m_epsilon(epsilon)
, m_viewportVect(params.viewportData.size(), VkViewport())
, m_scissorVect(params.viewportData.size(), VkRect2D())
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice device = m_context.getDevice();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const deUint32 viewportCount = static_cast<deUint32>(m_params.viewportData.size());
// create viewport grid
{
const deUint32 columnCount = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(viewportCount)));
const deUint32 rowCount = deCeilFloatToInt32(static_cast<float>(viewportCount) / static_cast<float>(columnCount));
const deUint32 rectWidth = WIDTH / columnCount;
const deUint32 rectHeight = HEIGHT / rowCount;
VkOffset2D pos { 0, 0 };
for (deUint32 viewportIndex = 0; viewportIndex < viewportCount; ++viewportIndex)
{
// move to next row
if ((viewportIndex != 0) && (viewportIndex % columnCount == 0))
{
pos.x = 0;
pos.y += rectHeight;
}
m_viewportVect[viewportIndex] =
{
static_cast<float>(pos.x), // float x;
static_cast<float>(pos.y), // float y;
static_cast<float>(rectWidth), // float width;
static_cast<float>(rectHeight), // float height;
m_params.viewportData[viewportIndex].minDepth, // float minDepth;
m_params.viewportData[viewportIndex].maxDepth, // float maxDepth;
};
m_scissorVect[viewportIndex] =
{
pos,
{rectWidth, rectHeight}
};
pos.x += rectWidth;
}
}
DescriptorPoolBuilder descriptorPoolBuilder;
DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
// Vertex data
{
const size_t verticesCount = DE_LENGTH_OF_ARRAY(vertices);
const VkDeviceSize dataSize = verticesCount * sizeof(Vec4);
m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
Vec4 testVertices[verticesCount];
deMemcpy(testVertices, vertices, dataSize);
for(size_t i = 0; i < verticesCount; ++i)
testVertices[i][2] = params.viewportData[0].depthValue;
deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), testVertices, static_cast<std::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_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const ImageCreateInfo targetImageCreateInfo (VK_IMAGE_TYPE_2D, m_format, { WIDTH, HEIGHT, 1u }, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, targetImageUsageFlags);
m_depthTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), queueFamilyIndex);
RenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.addAttachment(AttachmentDescription(
m_format, // 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_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // initialLayout
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
const VkAttachmentReference depthAttachmentReference = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
renderPassCreateInfo.addSubpass(SubpassDescription(
VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
(VkSubpassDescriptionFlags)0, // flags
0u, // inputAttachmentCount
DE_NULL, // inputAttachments
0u, // colorAttachmentCount
DE_NULL, // colorAttachments
DE_NULL, // resolveAttachments
depthAttachmentReference, // depthStencilAttachment
0u, // preserveAttachmentCount
DE_NULL)); // preserveAttachments
m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
}
const ImageViewCreateInfo depthTargetViewInfo (m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_format);
m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo);
const std::vector<VkImageView> depthAttachments { *m_depthTargetView };
FramebufferCreateInfo framebufferCreateInfo (*m_renderPass, depthAttachments, WIDTH, HEIGHT, 1);
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 Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
Move<VkShaderModule> geometryModule;
const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
if (viewportCount > 1)
geometryModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0);
const PipelineLayoutCreateInfo pipelineLayoutCreateInfo (0u, DE_NULL, 0u, DE_NULL);
m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
std::vector<VkDynamicState> dynamicStates { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
if (*geometryModule != 0)
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*geometryModule, "main", VK_SHADER_STAGE_GEOMETRY_BIT));
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState));
pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(verticesTopology));
pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (viewportCount, m_viewportVect, m_scissorVect));
pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState (VK_TRUE, VK_TRUE, VK_COMPARE_OP_ALWAYS, VK_FALSE, VK_FALSE));
pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState (
VK_TRUE, // depthClampEnable
VK_FALSE, // rasterizerDiscardEnable
VK_POLYGON_MODE_FILL, // polygonMode
VK_CULL_MODE_NONE, // cullMode
VK_FRONT_FACE_CLOCKWISE, // frontFace
m_params.enableDepthBias ? VK_TRUE : VK_FALSE, // depthBiasEnable
m_params.depthBiasConstantFactor, // depthBiasConstantFactor
0.0f, // depthBiasClamp
0.0f, // depthBiasSlopeFactor
1.0f)); // lineWidth
pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ());
pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState (dynamicStates));
m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
}
tcu::ConstPixelBufferAccess DepthClampTestInstance::draw ()
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice device = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
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));
const bool isCombinedType = tcu::isCombinedDepthStencilType(mapVkFormat(m_format).type) && m_format != VK_FORMAT_X8_D24_UNORM_PACK32;
beginCommandBuffer(vk, *cmdBuffer);
if (isCombinedType)
initialTransitionDepthStencil2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
else
initialTransitionDepth2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
const VkImageAspectFlagBits aspectBits = (VkImageAspectFlagBits)(isCombinedType ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT);
const ImageSubresourceRange subresourceRange (aspectBits);
const VkClearDepthStencilValue clearDepth = makeClearDepthStencilValue(initialClearDepth, 0u);
vk.cmdClearDepthStencilImage(*cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDepth, 1, &subresourceRange);
transition2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), aspectBits,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT , VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
{
const VkMemoryBarrier memBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT };
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
}
// if there is more then one viewport we are also checking
// proper behaviour of cmdSetViewport/Scissor - there was
// a driver bug that caused invalid behaviour of those
// functions when firstViewport/Scissor had a non 0 value
deUint32 indexCount = static_cast<deUint32>(m_viewportVect.size());
for (deUint32 index = 0 ; index < indexCount ; ++index)
{
vk.cmdSetViewport(*cmdBuffer, index, 1u, &m_viewportVect[index]);
vk.cmdSetScissor (*cmdBuffer, index, 1u, &m_scissorVect[index]);
}
beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT));
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
const VkDeviceSize offset = 0;
const VkBuffer buffer = m_vertexBuffer->object();
vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
vk.cmdDraw(*cmdBuffer, DE_LENGTH_OF_ARRAY(vertices), 1, 0, 0);
endRenderPass(vk, *cmdBuffer);
transition2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), aspectBits,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT , VK_ACCESS_MEMORY_READ_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT , VK_PIPELINE_STAGE_HOST_BIT);
endCommandBuffer(vk, *cmdBuffer);
submitCommandsAndWait(vk, device, queue, *cmdBuffer);
VK_CHECK(vk.queueWaitIdle(queue));
return m_depthTargetImage->readDepth(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { 0, 0, 0 }, WIDTH, HEIGHT, VK_IMAGE_ASPECT_DEPTH_BIT);
}
tcu::TestStatus DepthClampTestInstance::iterate (void)
{
const tcu::ConstPixelBufferAccess resultImage = draw();
DE_ASSERT((isUnormDepthFormat(m_format) == false) ||
(m_params.viewportData[0].expectedValue >= 0.0f && m_params.viewportData[0].expectedValue <= 1.0f));
for(deUint32 viewportIndex = 0 ; viewportIndex < m_scissorVect.size() ; ++viewportIndex)
{
const float expectedValue = m_params.viewportData[viewportIndex].expectedValue;
const VkRect2D& viewRect = m_scissorVect[viewportIndex];
deInt32 xStart = viewRect.offset.x;
deInt32 xEnd = xStart + viewRect.extent.width;
deInt32 yStart = viewRect.offset.y;
deInt32 yEnd = yStart + viewRect.extent.height;
for (int y = yStart; y < yEnd; ++y)
for (int x = xStart; x < xEnd; ++x)
{
if (std::abs(expectedValue - resultImage.getPixDepth(x, y, 0)) >= m_epsilon)
{
tcu::TestLog& log = m_context.getTestContext().getLog();
log << tcu::TestLog::ImageSet("Result of rendering", "")
<< tcu::TestLog::Image("Result", "", resultImage)
<< tcu::TestLog::EndImageSet;
std::ostringstream msg;
msg << "Depth value mismatch, expected: " << expectedValue
<< ", got: " << resultImage.getPixDepth(x, y, 0) << " at (" << x << ", " << y << ", 0)";
return tcu::TestStatus::fail(msg.str());
}
}
}
return tcu::TestStatus::pass("Pass");
}
class DepthClampTest : public TestCase
{
public:
DepthClampTest (tcu::TestContext &testCtx, const string& name, const string& description, const TestParams &params, const VkFormat format, const float epsilon)
: TestCase (testCtx, name, description)
, m_params(params)
, m_format(format)
, m_epsilon(epsilon)
{
}
virtual void initPrograms (SourceCollections& programCollection) const
{
programCollection.glslSources.add("vert") << glu::VertexSource(
"#version 450\n"
"\n"
"layout(location = 0) in vec4 in_position;\n"
"void main(void)\n"
"{\n"
" gl_Position = in_position;\n"
"}\n");
if (m_params.viewportData.size() > 1)
{
// gl_ViewportIndex built-in variable is available only to the geometry shader
std::string depthValues = "";
for (const auto& vd : m_params.viewportData)
depthValues += std::to_string(vd.depthValue) + ", ";
// this geometry shader draws the same quad but with diferent depth to all viewports
programCollection.glslSources.add("geom") << glu::GeometrySource(
std::string("#version 450\n") +
"#extension GL_EXT_geometry_shader : require\n"
"layout(invocations = " + std::to_string(m_params.viewportData.size()) + ") in;\n"
"layout(triangles) in;\n"
"layout(triangle_strip, max_vertices = 4) out;\n"
"void main()\n"
"{\n"
" const float depthValues[] = { " + depthValues + " 0.0 };\n"
" for (int i = 0; i < gl_in.length(); i++)\n"
" {\n"
" gl_ViewportIndex = gl_InvocationID;\n"
" gl_Position = gl_in[i].gl_Position;\n"
" gl_Position.z = depthValues[gl_InvocationID];\n"
" EmitVertex();\n"
" }\n"
" EndPrimitive();\n"
"}");
}
programCollection.glslSources.add("frag") << glu::FragmentSource(
"#version 450\n"
"void main(void)\n"
"{\n"
"}\n");
}
virtual void checkSupport (Context& context) const
{
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_CLAMP);
for(const auto& extensionName : m_params.requiredExtensions)
context.requireDeviceFunctionality(extensionName);
if (m_params.viewportData.size() > 1)
{
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
if (!context.getDeviceFeatures().geometryShader)
throw tcu::NotSupportedError("Geometry shader is not supported");
}
VkImageFormatProperties imageFormatProperties;
const auto& vki = context.getInstanceInterface();
const auto& vkd = context.getPhysicalDevice();
const auto usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (vki.getPhysicalDeviceImageFormatProperties(vkd, m_format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, 0u, &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
{
TCU_THROW(NotSupportedError, "Format not supported");
}
}
virtual TestInstance* createInstance (Context& context) const
{
return new DepthClampTestInstance(context, m_params, m_format, m_epsilon);
}
private:
const TestParams m_params;
const VkFormat m_format;
const float m_epsilon;
};
std::string getFormatCaseName (VkFormat format)
{
return de::toLower(de::toString(getFormatStr(format)).substr(10));
}
void createTests (tcu::TestCaseGroup* testGroup)
{
for(int i = 0; i < DE_LENGTH_OF_ARRAY(depthStencilImageFormatsToTest); ++i)
{
const auto format = depthStencilImageFormatsToTest[i];
const float epsilon = depthEpsilonValuesByFormat[i];
const auto formatCaseName = getFormatCaseName(format);
for(const auto& params : depthClearValuesToTest)
{
if ((params.skipSNorm && vk::isSnormFormat(format)) || (params.skipUNorm && isUnormDepthFormat(format)))
continue;
const auto testCaseName = formatCaseName + params.testNameSuffix;
testGroup->addChild(new DepthClampTest(testGroup->getTestContext(), testCaseName, "Depth clamp", params, format, epsilon));
}
}
}
} // anonymous
tcu::TestCaseGroup* createDepthClampTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "depth_clamp", "Depth Clamp Tests", createTests);
}
} // Draw
} // vkt