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