1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2023 The Khronos Group Inc. 6 * Copyright (c) 2023 Valve Corporation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief Test for VK_EXT_depth_bias_control. 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktRasterizationDepthBiasControlTests.hpp" 26#include "vktTestCase.hpp" 27 28#include "vkImageUtil.hpp" 29#include "vkObjUtil.hpp" 30#include "vkCmdUtil.hpp" 31#include "vkBarrierUtil.hpp" 32 33#include "tcuTextureUtil.hpp" 34#include "tcuImageCompare.hpp" 35 36#include "deUniquePtr.hpp" 37 38#include <sstream> 39#include <vector> 40#include <string> 41#include <cstring> 42 43namespace vkt 44{ 45namespace rasterization 46{ 47 48namespace 49{ 50 51using namespace vk; 52 53using MaybeRepr = tcu::Maybe<VkDepthBiasRepresentationInfoEXT>; 54 55VkDepthBiasRepresentationInfoEXT makeDepthBiasRepresentationInfo (const VkDepthBiasRepresentationEXT repr, const bool exact) 56{ 57 VkDepthBiasRepresentationInfoEXT info = initVulkanStructure(); 58 info.depthBiasRepresentation = repr; 59 info.depthBiasExact = (exact ? VK_TRUE : VK_FALSE); 60 return info; 61} 62 63std::string getFormatNameShort (const VkFormat format) 64{ 65 static const size_t prefixLen = std::strlen("VK_FORMAT_"); 66 const auto fullName = getFormatName(format); 67 const auto shortName = de::toLower(std::string(fullName).substr(prefixLen)); 68 return shortName; 69} 70 71inline tcu::IVec3 getExtent (void) { return tcu::IVec3(1, 1, 1); } 72inline VkImageUsageFlags getColorUsage (void) { return (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); } 73inline VkImageUsageFlags getDepthUsage (void) { return (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); } 74 75VkImageCreateInfo getImageCreateInfo (const VkFormat format, const VkExtent3D& extent, const VkImageUsageFlags usage) 76{ 77 const VkImageCreateInfo imageCreateInfo 78 { 79 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 80 nullptr, // const void* pNext; 81 0u, // VkImageCreateFlags flags; 82 VK_IMAGE_TYPE_2D, // VkImageType imageType; 83 format, // VkFormat format; 84 extent, // VkExtent3D extent; 85 1u, // uint32_t mipLevels; 86 1u, // uint32_t arrayLayers; 87 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 88 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 89 usage, // VkImageUsageFlags usage; 90 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 91 0u, // uint32_t queueFamilyIndexCount; 92 nullptr, // const uint32_t* pQueueFamilyIndices; 93 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 94 }; 95 96 return imageCreateInfo; 97} 98 99using MinResolvDiff = std::pair<double, double>; // Min and Max values. 100 101double calcPowerOf2 (int exponent) 102{ 103 if (exponent >= 0) 104 return static_cast<double>(1u << exponent); 105 return (1.0 / static_cast<double>(1u << (-exponent))); 106} 107 108tcu::TextureChannelClass getChannelClass (const tcu::TextureFormat& format) 109{ 110 const auto generalClass = getTextureChannelClass(format.type); 111 // Fix for VK_FORMAT_X8_D24_UNORM_PACK32 112 return ((generalClass == tcu::TEXTURECHANNELCLASS_LAST) ? tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT : generalClass); 113} 114 115// Returns a couple of numbers with the minimum and maximum values R (minimum resolvable difference) can have according to the spec. 116// As explained there, this depends on the depth attachment format, the depth bias representation parameters and sometimes the 117// geometry itself. 118MinResolvDiff calcMinResolvableDiff (const tcu::TextureFormat& format, const VkDepthBiasRepresentationEXT repr, bool exact, float sampleDepth) 119{ 120 MinResolvDiff r (0.0, 0.0); 121 const auto channelClass = getChannelClass(format); 122 123 switch (repr) 124 { 125 case VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT: 126 if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 127 { 128 // Up to r = 2x2^(-n) where n is bit width. 129 const auto bitDepth = getTextureFormatBitDepth(format); 130 const double minR = calcPowerOf2(-bitDepth[0]); 131 132 r.first = minR; 133 r.second = (exact ? 1.0 : 2.0) * minR; 134 } 135 else if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) 136 { 137 // r = 2^(e-n): e is max exponent in z values, n is mantissa bits. 138 const tcu::Float32 value (sampleDepth); 139 const int exponent = value.exponent() - tcu::Float32::MANTISSA_BITS; // (e-n) 140 const double minR = calcPowerOf2(exponent); 141 142 r.first = minR; 143 r.second = minR; 144 } 145 else 146 DE_ASSERT(false); 147 break; 148 case VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT: 149 { 150 // Up to r = 2x2^(-n), where n is the bit width for fixed-point formats or the number of mantissa bits plus one for 151 // floating-point formats. 152 int n = 0; 153 154 if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 155 n = getTextureFormatBitDepth(format)[0]; 156 else if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) 157 n = tcu::Float32::MANTISSA_BITS + 1; 158 else 159 DE_ASSERT(false); 160 161 DE_ASSERT(n > 0); // Make sure the bitwidth is positive. 162 const double minR = calcPowerOf2(-n); 163 164 r.first = minR; 165 r.second = (exact ? 1.0 : 2.0) * minR; 166 } 167 break; 168 case VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT: 169 // r is always 1. 170 r.first = 1.0; 171 r.second = 1.0; 172 break; 173 default: 174 DE_ASSERT(false); 175 break; 176 } 177 178 return r; 179} 180 181// Calculates error threshold when representing values in the given format. This is equivalent to calculating the minimum resolvable 182// difference R according to the format, with exact precision. 183double getDepthErrorThreshold (const tcu::TextureFormat& format, const float sampleDepth) 184{ 185 const auto r = calcMinResolvableDiff(format, VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, true, sampleDepth); 186 return r.first; 187} 188 189// Which depth bias factor will be used in the tests: focus on depthBiasSlopeFactor or depthBiasConstantFactor. 190enum class UsedFactor { SLOPE = 0, CONSTANT = 1 }; 191 192// How are we going to set the depth bias parameters: statically or dynamically. 193enum class SetMechanism { STATIC = 0, DYNAMIC_1 = 1 /*vkCmdSetDepthBias*/, DYNAMIC_2 = 2 /*vkCmdSetDepthBias2*/}; 194 195std::string getMechanismName (const SetMechanism m) 196{ 197 switch (m) 198 { 199 case SetMechanism::STATIC: return "Static"; 200 case SetMechanism::DYNAMIC_1: return "vkCmdSetDepthBias"; 201 case SetMechanism::DYNAMIC_2: return "vkCmdSetDepthBias2"; 202 default: break; 203 } 204 205 DE_ASSERT(false); 206 return ""; 207} 208 209struct TestParams 210{ 211 const VkFormat attachmentFormat; // Depth attachment format. 212 const MaybeRepr reprInfo; // Representation info. We omit it for some cases. 213 const SetMechanism setMechanism; 214 const float targetBias; // The bias we aim to get, before clamping. Based on this and R, we can calculate factors. 215 const UsedFactor usedFactor; 216 const float constantDepth; // When using UsedFactor::CONSTANT. 217 const float depthBiasClamp; 218 const bool secondaryCmdBuffer; // Use secondary command buffers or not. 219 220 void log (tcu::TestLog& testLog) const 221 { 222 testLog << tcu::TestLog::Message << "Depth format: " << attachmentFormat << tcu::TestLog::EndMessage; 223 224 if (!reprInfo) 225 testLog << tcu::TestLog::Message << "No VkDepthBiasRepresentationInfoEXT extension structure" << tcu::TestLog::EndMessage; 226 else 227 testLog << tcu::TestLog::Message << *reprInfo << tcu::TestLog::EndMessage; 228 229 testLog 230 << tcu::TestLog::Message << "Set mechanism: " << getMechanismName(setMechanism) << tcu::TestLog::EndMessage 231 << tcu::TestLog::Message << "Target bias: " << targetBias << tcu::TestLog::EndMessage 232 << tcu::TestLog::Message << "Used factor: " << ((usedFactor == UsedFactor::SLOPE) ? "depthBiasSlopeFactor" : "depthBiasConstantFactor") << tcu::TestLog::EndMessage 233 ; 234 235 if (usedFactor == UsedFactor::SLOPE) 236 testLog << tcu::TestLog::Message << "Maximum depth slope: " << 1.0f << tcu::TestLog::EndMessage; 237 else 238 testLog << tcu::TestLog::Message << "Constant depth: " << constantDepth << tcu::TestLog::EndMessage; 239 240 testLog << tcu::TestLog::Message << "Depth bias clamp: " << depthBiasClamp << tcu::TestLog::EndMessage; 241 } 242}; 243 244class DepthBiasControlInstance : public vkt::TestInstance 245{ 246public: 247 DepthBiasControlInstance (Context& context, const TestParams& params) 248 : vkt::TestInstance (context) 249 , m_params (params) 250 {} 251 virtual ~DepthBiasControlInstance (void) {} 252 253 tcu::TestStatus iterate (void) override; 254 255protected: 256 const TestParams m_params; 257}; 258 259class DepthBiasControlCase : public vkt::TestCase 260{ 261public: 262 static tcu::Vec4 kOutColor; 263 264 DepthBiasControlCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params) 265 : vkt::TestCase (testCtx, name) 266 , m_params (params) 267 {} 268 virtual ~DepthBiasControlCase (void) {} 269 270 void initPrograms (vk::SourceCollections& programCollection) const override; 271 TestInstance* createInstance (Context& context) const override; 272 void checkSupport (Context& context) const override; 273 274protected: 275 const TestParams m_params; 276}; 277 278tcu::Vec4 DepthBiasControlCase::kOutColor (0.0f, 0.0f, 1.0f, 1.0f); 279 280void DepthBiasControlCase::checkSupport (Context &context) const 281{ 282 context.requireDeviceFunctionality("VK_EXT_depth_bias_control"); 283 284 if (m_params.reprInfo) 285 { 286 const auto& reprInfo = m_params.reprInfo.get(); 287 const auto& dbcFeatures = context.getDepthBiasControlFeaturesEXT(); 288 289 if (reprInfo.depthBiasExact && !dbcFeatures.depthBiasExact) 290 TCU_THROW(NotSupportedError, "depthBiasExact not supported"); 291 292 if (reprInfo.depthBiasRepresentation == VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT 293 && !dbcFeatures.leastRepresentableValueForceUnormRepresentation) 294 { 295 TCU_THROW(NotSupportedError, "leastRepresentableValueForceUnormRepresentation not supported"); 296 } 297 298 if (reprInfo.depthBiasRepresentation == VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT && !dbcFeatures.floatRepresentation) 299 TCU_THROW(NotSupportedError, "floatRepresentation not supported"); 300 } 301 302 // Check format support. 303 const auto& vki = context.getInstanceInterface(); 304 const auto physDev = context.getPhysicalDevice(); 305 306 const auto imageExtent = makeExtent3D(getExtent()); 307 const auto imageUsage = getDepthUsage(); 308 const auto imageCreateInfo = getImageCreateInfo(m_params.attachmentFormat, imageExtent, imageUsage); 309 310 VkImageFormatProperties formatProperties; 311 const auto formatSupport = vki.getPhysicalDeviceImageFormatProperties(physDev, m_params.attachmentFormat, imageCreateInfo.imageType, imageCreateInfo.tiling, imageUsage, imageCreateInfo.flags, &formatProperties); 312 if (formatSupport == VK_ERROR_FORMAT_NOT_SUPPORTED) 313 TCU_THROW(NotSupportedError, getFormatNameShort(m_params.attachmentFormat) + " not supported"); 314} 315 316TestInstance* DepthBiasControlCase::createInstance (Context& context) const 317{ 318 return new DepthBiasControlInstance(context, m_params); 319} 320 321void DepthBiasControlCase::initPrograms (vk::SourceCollections &programCollection) const 322{ 323 std::ostringstream vert; 324 vert 325 << "#version 460\n" 326 << "layout (location=0) in vec4 inPos;\n" 327 << "void main (void) {\n" 328 << " gl_Position = inPos;\n" 329 << "}\n" 330 ; 331 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); 332 333 std::ostringstream frag; 334 frag 335 << "#version 460\n" 336 << "layout (location=0) out vec4 outColor;\n" 337 << "void main (void) {\n" 338 << " outColor = vec4" << kOutColor << ";\n" 339 << "}\n" 340 ; 341 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); 342} 343 344tcu::TestStatus DepthBiasControlInstance::iterate (void) 345{ 346 const auto ctx = m_context.getContextCommonData(); 347 const tcu::IVec3 fbExtent (1, 1, 1); 348 const auto vkExtent = makeExtent3D(fbExtent); 349 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 350 const auto colorUsage = getColorUsage(); 351 const auto depthFormat = m_params.attachmentFormat; 352 const auto depthUsage = getDepthUsage(); 353 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 354 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 355 const auto depthSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u); 356 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); 357 const auto depthSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u); 358 const auto tcuDepthFormat = getDepthCopyFormat(depthFormat); 359 const auto tcuColorFormat = mapVkFormat(colorFormat); 360 const bool setStatically = (m_params.setMechanism == SetMechanism::STATIC); 361 auto& log = m_context.getTestContext().getLog(); 362 363 const auto colorCreateInfo = getImageCreateInfo(colorFormat, vkExtent, colorUsage); 364 const auto depthCreateInfo = getImageCreateInfo(depthFormat, vkExtent, depthUsage); 365 366 // Color buffer. 367 ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, colorCreateInfo.imageType, colorSRR, 368 colorCreateInfo.arrayLayers, colorCreateInfo.samples, colorCreateInfo.tiling, colorCreateInfo.mipLevels, colorCreateInfo.sharingMode); 369 370 // Depth buffer. 371 ImageWithBuffer depthBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, depthFormat, depthUsage, depthCreateInfo.imageType, depthSRR, 372 depthCreateInfo.arrayLayers, depthCreateInfo.samples, depthCreateInfo.tiling, depthCreateInfo.mipLevels, depthCreateInfo.sharingMode); 373 374 // Vertices and vertex buffer. 375 // 376 // Generate two triangles as a triangle strip covering the whole framebuffer (4 vertices). 377 // +--+ 378 // | /| 379 // |/ | 380 // +--+ 381 // 382 // WHEN USING THE DEPTH SLOPE FACTOR: 383 // If the framebuffer is 1x1, the delta-X and delta-Y accross the whole framebuffer is 1. 384 // If we make the left-side vertices have a depth of 1.0 and the other 2 have 0.0, delta-Z is 1. 385 // Using both alternative formulas for calculating M, M is 1. This means depthSlopeFactor applies directly. 386 // The depth at the sampling point would be 0.5. 387 // 388 // WHEN USING THE CONSTANT FACTOR: 389 // Generate geometry with a chosen constant depth, so M is zero and depthSlopeFactor never applies. 390 // We will make depthSlopeFactor 0 in any case. 391 // The constant depth value allows us to control the depth value exponent, which affects some calculations. 392 const std::vector<tcu::Vec4> vertices 393 { 394 tcu::Vec4(-1.0f, -1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.0f), 1.0f), 395 tcu::Vec4(-1.0f, 1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.0f), 1.0f), 396 tcu::Vec4( 1.0f, -1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 1.0f), 1.0f), 397 tcu::Vec4( 1.0f, 1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 1.0f), 1.0f), 398 }; 399 const float sampleDepth = ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.5f); 400 401 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices)); 402 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); 403 BufferWithMemory vertexBuffer (ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible); 404 auto& vertexAlloc = vertexBuffer.getAllocation(); 405 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0); 406 407 deMemcpy(vertexAlloc.getHostPtr(), de::dataOrNull(vertices), de::dataSize(vertices)); 408 flushAlloc(ctx.vkd, ctx.device, vertexAlloc); 409 410 // Render pass with depth attachment. 411 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat, depthFormat); 412 413 // Framebuffer. 414 const std::vector<VkImageView> imageViews 415 { 416 colorBuffer.getImageView(), 417 depthBuffer.getImageView(), 418 }; 419 420 const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, renderPass.get(), 421 de::sizeU32(imageViews), de::dataOrNull(imageViews), 422 vkExtent.width, vkExtent.height); 423 424 // Pipeline. 425 const auto& binaries = m_context.getBinaryCollection(); 426 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert")); 427 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag")); 428 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device); 429 430 // Viewports and scissors. 431 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent)); 432 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent)); 433 434 // Calculate depth bias parameters. 435 const auto representation = (m_params.reprInfo ? m_params.reprInfo->depthBiasRepresentation : VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT); 436 const bool exactRepr = (m_params.reprInfo ? m_params.reprInfo->depthBiasExact : false); 437 const auto rValue = calcMinResolvableDiff(tcuDepthFormat, representation, exactRepr, sampleDepth); 438 439 // Calculate factors based on the target bias and the minimum resolvable difference. 440 const float depthBiasConstantFactor = ((m_params.usedFactor == UsedFactor::CONSTANT) ? static_cast<float>(static_cast<double>(m_params.targetBias) / rValue.first) : 0.0f); 441 const float depthBiasSlopeFactor = ((m_params.usedFactor == UsedFactor::SLOPE) ? m_params.targetBias : 0.0f); // Note M is 1. 442 const float depthBiasClamp = m_params.depthBiasClamp; 443 { 444 // Log some interesting test details, including computed factors. 445 m_params.log(log); 446 log 447 << tcu::TestLog::Message << "Rmin: " << rValue.first << tcu::TestLog::EndMessage 448 << tcu::TestLog::Message << "Rmax: " << rValue.second << tcu::TestLog::EndMessage 449 << tcu::TestLog::Message << "depthBiasConstantFactor: " << depthBiasConstantFactor << tcu::TestLog::EndMessage 450 << tcu::TestLog::Message << "depthBiasSlopeFactor: " << depthBiasSlopeFactor << tcu::TestLog::EndMessage 451 << tcu::TestLog::Message << "depthBiasClamp: " << depthBiasClamp << tcu::TestLog::EndMessage 452 ; 453 } 454 455 const void* rasterizationPnext = ((setStatically && m_params.reprInfo) ? &m_params.reprInfo.get() : nullptr); 456 457 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = 458 { 459 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; 460 rasterizationPnext, // const void* pNext; 461 0u, // VkPipelineRasterizationStateCreateFlags flags; 462 VK_FALSE, // VkBool32 depthClampEnable; 463 VK_FALSE, // VkBool32 rasterizerDiscardEnable; 464 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; 465 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode; 466 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; 467 VK_TRUE, // VkBool32 depthBiasEnable; 468 (setStatically ? depthBiasConstantFactor : 0.0f), // float depthBiasConstantFactor; 469 (setStatically ? depthBiasClamp : 0.0f), // float depthBiasClamp; 470 (setStatically ? depthBiasSlopeFactor : 0.0f), // float depthBiasSlopeFactor; 471 1.0f, // float lineWidth; 472 }; 473 474 const auto stencilOp = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0xFFu); 475 476 const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = 477 { 478 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; 479 nullptr, // const void* pNext; 480 0u, // VkPipelineDepthStencilStateCreateFlags flags; 481 VK_TRUE, // VkBool32 depthTestEnable; 482 VK_TRUE, // VkBool32 depthWriteEnable; 483 VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp; 484 VK_FALSE, // VkBool32 depthBoundsTestEnable; 485 VK_FALSE, // VkBool32 stencilTestEnable; 486 stencilOp, // VkStencilOpState front; 487 stencilOp, // VkStencilOpState back; 488 0.0f, // float minDepthBounds; 489 1.0f, // float maxDepthBounds; 490 }; 491 492 std::vector<VkDynamicState> dynamicStates; 493 if (!setStatically) 494 dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); 495 496 const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = 497 { 498 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; 499 nullptr, // const void* pNext; 500 0u, // VkPipelineDynamicStateCreateFlags flags; 501 de::sizeU32(dynamicStates), // uint32_t dynamicStateCount; 502 de::dataOrNull(dynamicStates), // const VkDynamicState* pDynamicStates; 503 }; 504 505 const auto pipeline = makeGraphicsPipeline( 506 ctx.vkd, ctx.device, pipelineLayout.get(), 507 vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(), 508 renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u, 509 nullptr, &rasterizationStateCreateInfo, nullptr, &depthStencilStateCreateInfo, nullptr, &dynamicStateCreateInfo); 510 511 // Command buffers. 512 CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex); 513 const auto primaryCmdBuffer = cmd.cmdBuffer.get(); 514 515 // Optional secondary command buffer 516 const auto secondaryCmdBufferPtr = (m_params.secondaryCmdBuffer 517 ? allocateCommandBuffer(ctx.vkd, ctx.device, cmd.cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY) 518 : Move<VkCommandBuffer>()); 519 const auto secondaryCmdBuffer = (m_params.secondaryCmdBuffer ? secondaryCmdBufferPtr.get() : VK_NULL_HANDLE); 520 const auto subpassContents = (m_params.secondaryCmdBuffer ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE); 521 522 // For render pass contents. 523 const auto rpCmdBuffer = (m_params.secondaryCmdBuffer ? secondaryCmdBuffer : primaryCmdBuffer); 524 525 const std::vector<VkClearValue> clearValues 526 { 527 makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)), 528 makeClearValueDepthStencil(1.0f, 0u), 529 }; 530 531 beginCommandBuffer(ctx.vkd, primaryCmdBuffer); 532 if (m_params.secondaryCmdBuffer) 533 beginSecondaryCommandBuffer(ctx.vkd, secondaryCmdBuffer, renderPass.get(), framebuffer.get()); 534 beginRenderPass(ctx.vkd, primaryCmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues), subpassContents); 535 536 // Render pass contents. 537 ctx.vkd.cmdBindVertexBuffers(rpCmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); 538 ctx.vkd.cmdBindPipeline(rpCmdBuffer, bindPoint, pipeline.get()); 539 if (!setStatically) 540 { 541 if (m_params.setMechanism == SetMechanism::DYNAMIC_1) 542 { 543 DE_ASSERT(!m_params.reprInfo); 544 ctx.vkd.cmdSetDepthBias(rpCmdBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); 545 } 546 else if (m_params.setMechanism == SetMechanism::DYNAMIC_2) 547 { 548 const void* biasInfoPnext = (m_params.reprInfo ? &m_params.reprInfo.get() : nullptr); 549 550 const VkDepthBiasInfoEXT depthBiasInfo = 551 { 552 VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT, // VkStructureType sType; 553 biasInfoPnext, // const void* pNext; 554 depthBiasConstantFactor, // float depthBiasConstantFactor; 555 depthBiasClamp, // float depthBiasClamp; 556 depthBiasSlopeFactor, // float depthBiasSlopeFactor; 557 }; 558 ctx.vkd.cmdSetDepthBias2EXT(rpCmdBuffer, &depthBiasInfo); 559 } 560 else 561 DE_ASSERT(false); 562 } 563 ctx.vkd.cmdDraw(rpCmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u); 564 565 if (m_params.secondaryCmdBuffer) 566 { 567 endCommandBuffer(ctx.vkd, secondaryCmdBuffer); 568 ctx.vkd.cmdExecuteCommands(primaryCmdBuffer, 1u, &secondaryCmdBuffer); 569 } 570 endRenderPass(ctx.vkd, primaryCmdBuffer); 571 572 // Copy color and depth buffers to their verification buffers. 573 { 574 const std::vector<VkImageMemoryBarrier> preTransferBarriers 575 { 576 makeImageMemoryBarrier( 577 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 578 VK_ACCESS_TRANSFER_READ_BIT, 579 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 580 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 581 depthBuffer.getImage(), depthSRR), 582 583 makeImageMemoryBarrier( 584 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 585 VK_ACCESS_TRANSFER_READ_BIT, 586 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 587 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 588 colorBuffer.getImage(), colorSRR), 589 }; 590 591 const auto preTransferStages = (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); 592 cmdPipelineImageMemoryBarrier(ctx.vkd, primaryCmdBuffer, preTransferStages, VK_PIPELINE_STAGE_TRANSFER_BIT, de::dataOrNull(preTransferBarriers), de::sizeU32(preTransferBarriers)); 593 594 const auto depthRegion = makeBufferImageCopy(vkExtent, depthSRL); 595 const auto colorRegion = makeBufferImageCopy(vkExtent, colorSRL); 596 597 ctx.vkd.cmdCopyImageToBuffer(primaryCmdBuffer, depthBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depthBuffer.getBuffer(), 1u, &depthRegion); 598 ctx.vkd.cmdCopyImageToBuffer(primaryCmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getBuffer(), 1u, &colorRegion); 599 600 const auto transfer2Host = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 601 cmdPipelineMemoryBarrier(ctx.vkd, primaryCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &transfer2Host); 602 } 603 604 endCommandBuffer(ctx.vkd, primaryCmdBuffer); 605 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, primaryCmdBuffer); 606 607 // Invalidate allocations and verify contents. 608 invalidateAlloc(ctx.vkd, ctx.device, depthBuffer.getBufferAllocation()); 609 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation()); 610 611 // Depth reference. 612 tcu::TextureLevel depthReferenceLevel (tcuDepthFormat, fbExtent.x(), fbExtent.y()); 613 tcu::PixelBufferAccess depthReferenceAccess (depthReferenceLevel.getAccess()); 614 const bool noClamp = (m_params.depthBiasClamp == 0.0f); 615 const float clampedBias = std::min(m_params.targetBias, (noClamp ? m_params.targetBias : m_params.depthBiasClamp)); 616 const float expectedDepth = sampleDepth + clampedBias; // Must match vertex depth + actual bias. 617 tcu::clearDepth(depthReferenceAccess, expectedDepth); 618 619 // We calculated depth bias constant factors based on the most precise minimum resolvable diff, but the actual resolvable diff 620 // may be bigger in some cases. We take that into account when calculating the error threshold for depth values, and we add the 621 // format precision on top. 622 const double constantFactorD = static_cast<double>(depthBiasConstantFactor); 623 const double constantBiasMin = constantFactorD * rValue.first; 624 const double constantBiasMax = constantFactorD * rValue.second; 625 const double constantBiasErrorThres = constantBiasMax - constantBiasMin; 626 const float depthThreshold = static_cast<float>(constantBiasErrorThres + getDepthErrorThreshold(tcuDepthFormat, expectedDepth)); 627 { 628 log 629 << tcu::TestLog::Message << "Constant Bias Min: " << constantBiasMin << tcu::TestLog::EndMessage 630 << tcu::TestLog::Message << "Constant Bias Max: " << constantBiasMax << tcu::TestLog::EndMessage 631 << tcu::TestLog::Message << "Constant Bias Error Threshold: " << constantBiasErrorThres << tcu::TestLog::EndMessage 632 ; 633 } 634 635 // Color reference. 636 const tcu::Vec4& expectedColor = DepthBiasControlCase::kOutColor; 637 const tcu::Vec4 colorThreshold (0.0f, 0.0f, 0.0f, 0.0f); // Expect exact result in color. 638 639 // Result pixel buffer accesses. 640 const tcu::ConstPixelBufferAccess depthResultAccess (tcuDepthFormat, fbExtent, depthBuffer.getBufferAllocation().getHostPtr()); 641 const tcu::ConstPixelBufferAccess colorResultAccess (tcuColorFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr()); 642 643 bool fail = false; 644 645 if (!tcu::dsThresholdCompare(log, "DepthResult", "", depthReferenceAccess, depthResultAccess, depthThreshold, tcu::COMPARE_LOG_ON_ERROR)) 646 { 647 log << tcu::TestLog::Message << "Depth buffer failed: expected " << expectedDepth << " (threshold " << depthThreshold 648 << ") and found " << depthResultAccess.getPixDepth(0, 0) << tcu::TestLog::EndMessage; 649 fail = true; 650 } 651 652 if (!tcu::floatThresholdCompare(log, "ColorResult", "", expectedColor, colorResultAccess, colorThreshold, tcu::COMPARE_LOG_ON_ERROR)) 653 { 654 log << tcu::TestLog::Message << "Color buffer failed: expected " << expectedColor << " (threshold " << colorThreshold 655 << ") and found " << depthResultAccess.getPixel(0, 0) << tcu::TestLog::EndMessage; 656 fail = true; 657 } 658 659 if (fail) 660 return tcu::TestStatus::fail("Failed -- check log for details"); 661 return tcu::TestStatus::pass("Pass"); 662} 663 664} // anonymous namespace 665 666tcu::TestCaseGroup* createDepthBiasControlTests (tcu::TestContext& testCtx) 667{ 668 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>; 669 670 const std::vector<VkFormat> attachmentFormats 671 { 672 VK_FORMAT_D16_UNORM, 673 VK_FORMAT_X8_D24_UNORM_PACK32, 674 VK_FORMAT_D32_SFLOAT, 675 VK_FORMAT_D16_UNORM_S8_UINT, 676 VK_FORMAT_D24_UNORM_S8_UINT, 677 VK_FORMAT_D32_SFLOAT_S8_UINT, 678 }; 679 680 const struct 681 { 682 const UsedFactor usedFactor; 683 const char* name; 684 } usedFactorCases[] = 685 { 686 { UsedFactor::SLOPE, "slope" }, 687 { UsedFactor::CONSTANT, "constant" }, 688 }; 689 690 const struct 691 { 692 const MaybeRepr reprInfo; 693 const char* name; 694 } reprInfoCases[] = 695 { 696 { tcu::Nothing, "no_repr_info" }, 697 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false), "format_inexact" }, 698 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, true), "format_exact" }, 699 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT, false), "force_unorm_inexact" }, 700 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT, true), "force_unorm_exact" }, 701 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT, false), "float_inexact" }, 702 { makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT, true), "float_exact" }, 703 }; 704 705 struct ConstantDepthCase 706 { 707 const float constantDepth; 708 const char* name; 709 }; 710 using ConstantDepthCaseVec = std::vector<ConstantDepthCase>; 711 712 const ConstantDepthCaseVec constantDepthSlopeCases // For these subcases, the constant depth is not used. 713 { 714 { 0.0f, "slope_depth_1_0" }, 715 }; 716 const ConstantDepthCaseVec constantDepthConstantCases 717 { 718 { 0.25f, "constant_depth_0_25" }, 719 { 0.3125f, "constant_depth_0_3125" }, 720 { 0.489742279053f, "constant_depth_close_to_0_5" }, 721 { 0.625f, "constant_depth_0_625" }, 722 { 0.125f, "constant_depth_0_125" }, 723 }; 724 725 const struct 726 { 727 const float targetBias; 728 const char* name; 729 } targetBiasCases[] = 730 { 731 { 0.0625f, "target_bias_0_0625" }, 732 { 0.125f, "target_bias_0_125" }, 733 { 0.25f, "target_bias_0_25" }, 734 }; 735 736 const struct 737 { 738 const SetMechanism setMechanism; 739 const char* name; 740 } setMechanismCases[] = 741 { 742 { SetMechanism::STATIC, "static" }, 743 { SetMechanism::DYNAMIC_1, "dynamic_set_1" }, 744 { SetMechanism::DYNAMIC_2, "dynamic_set_2" }, 745 }; 746 747 enum class ClampCase { ZERO = 0, LARGE = 1, SMALL = 2 }; 748 const struct 749 { 750 const ClampCase clampCase; 751 const char* suffix; 752 } clampValueCases[] = 753 { 754 { ClampCase::ZERO, "_no_clamp" }, 755 { ClampCase::LARGE, "_no_effective_clamp" }, 756 { ClampCase::SMALL, "_clamp_to_half" }, 757 }; 758 759 const struct 760 { 761 const bool secondaryCmdBuffer; 762 const char* suffix; 763 } secondaryCmdBufferCases[] = 764 { 765 { false, "" }, 766 { true, "_secondary_cmd_buffer" }, 767 }; 768 769 GroupPtr dbcGroup (new tcu::TestCaseGroup(testCtx, "depth_bias_control")); 770 771 for (const auto& format : attachmentFormats) 772 { 773 const auto formatName = getFormatNameShort(format); 774 775 GroupPtr formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str())); 776 777 for (const auto& reprInfoCase : reprInfoCases) 778 { 779 GroupPtr reprInfoGroup (new tcu::TestCaseGroup(testCtx, reprInfoCase.name)); 780 781 for (const auto& usedFactorCase : usedFactorCases) 782 { 783 GroupPtr usedFactorGroup (new tcu::TestCaseGroup(testCtx, usedFactorCase.name)); 784 785 const bool constantFactor = (usedFactorCase.usedFactor == UsedFactor::CONSTANT); 786 const ConstantDepthCaseVec& constantDepthCases = (constantFactor ? constantDepthConstantCases : constantDepthSlopeCases); 787 788 for (const auto& constantDepthCase : constantDepthCases) 789 { 790 GroupPtr constantDepthGroup (new tcu::TestCaseGroup(testCtx, constantDepthCase.name)); 791 792 for (const auto& targetBiasCase : targetBiasCases) 793 { 794 GroupPtr targetBiasGroup (new tcu::TestCaseGroup(testCtx, targetBiasCase.name)); 795 796 for (const auto& setMechanismCase : setMechanismCases) 797 { 798 // We cannot use the representation info with vkCmdSetDepthBias. 799 if (setMechanismCase.setMechanism == SetMechanism::DYNAMIC_1 && static_cast<bool>(reprInfoCase.reprInfo)) 800 continue; 801 802 for (const auto& clampValueCase : clampValueCases) 803 { 804 float depthBiasClamp = 0.0f; 805 switch (clampValueCase.clampCase) 806 { 807 case ClampCase::ZERO: depthBiasClamp = 0.0f; break; 808 case ClampCase::LARGE: depthBiasClamp = targetBiasCase.targetBias * 2.0f; break; 809 case ClampCase::SMALL: depthBiasClamp = targetBiasCase.targetBias * 0.5f; break; 810 default: DE_ASSERT(false); break; 811 } 812 813 for (const auto& secondaryCmdBufferCase : secondaryCmdBufferCases) 814 { 815 // Some selected combinations will use secondary command buffers. Avoid applying this to all 816 // combinations to keep the number of cases low. 817 if (secondaryCmdBufferCase.secondaryCmdBuffer) 818 { 819 if (usedFactorCase.usedFactor != UsedFactor::CONSTANT) 820 continue; 821 822 if (setMechanismCase.setMechanism == SetMechanism::DYNAMIC_1) 823 continue; 824 825 if (clampValueCase.clampCase != ClampCase::ZERO) 826 continue; 827 828 if (!static_cast<bool>(reprInfoCase.reprInfo)) 829 continue; 830 } 831 832 const TestParams params 833 { 834 format, 835 reprInfoCase.reprInfo, 836 setMechanismCase.setMechanism, 837 targetBiasCase.targetBias, 838 usedFactorCase.usedFactor, 839 constantDepthCase.constantDepth, 840 depthBiasClamp, 841 secondaryCmdBufferCase.secondaryCmdBuffer, 842 }; 843 const std::string testName = std::string(setMechanismCase.name) + clampValueCase.suffix + secondaryCmdBufferCase.suffix; 844 targetBiasGroup->addChild(new DepthBiasControlCase(testCtx, testName, params)); 845 } 846 } 847 } 848 849 constantDepthGroup->addChild(targetBiasGroup.release()); 850 } 851 852 usedFactorGroup->addChild(constantDepthGroup.release()); 853 } 854 855 reprInfoGroup->addChild(usedFactorGroup.release()); 856 } 857 858 formatGroup->addChild(reprInfoGroup.release()); 859 } 860 861 dbcGroup->addChild(formatGroup.release()); 862 } 863 864 return dbcGroup.release(); 865} 866 867} // rasterization 868} // vkt 869