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
43 namespace vkt
44 {
45 namespace rasterization
46 {
47
48 namespace
49 {
50
51 using namespace vk;
52
53 using MaybeRepr = tcu::Maybe<VkDepthBiasRepresentationInfoEXT>;
54
makeDepthBiasRepresentationInfo(const VkDepthBiasRepresentationEXT repr,const bool exact)55 VkDepthBiasRepresentationInfoEXT 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
getFormatNameShort(const VkFormat format)63 std::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
getExtent(void)71 inline tcu::IVec3 getExtent (void) { return tcu::IVec3(1, 1, 1); }
getColorUsage(void)72 inline VkImageUsageFlags getColorUsage (void) { return (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); }
getDepthUsage(void)73 inline VkImageUsageFlags getDepthUsage (void) { return (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); }
74
getImageCreateInfo(const VkFormat format,const VkExtent3D & extent,const VkImageUsageFlags usage)75 VkImageCreateInfo 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
99 using MinResolvDiff = std::pair<double, double>; // Min and Max values.
100
calcPowerOf2(int exponent)101 double 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
getChannelClass(const tcu::TextureFormat & format)108 tcu::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.
calcMinResolvableDiff(const tcu::TextureFormat & format,const VkDepthBiasRepresentationEXT repr,bool exact,float sampleDepth)118 MinResolvDiff 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.
getDepthErrorThreshold(const tcu::TextureFormat & format,const float sampleDepth)183 double 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.
190 enum class UsedFactor { SLOPE = 0, CONSTANT = 1 };
191
192 // How are we going to set the depth bias parameters: statically or dynamically.
193 enum class SetMechanism { STATIC = 0, DYNAMIC_1 = 1 /*vkCmdSetDepthBias*/, DYNAMIC_2 = 2 /*vkCmdSetDepthBias2*/};
194
getMechanismName(const SetMechanism m)195 std::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
209 struct 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
logvkt::rasterization::__anone2f729880111::TestParams220 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
244 class DepthBiasControlInstance : public vkt::TestInstance
245 {
246 public:
DepthBiasControlInstance(Context & context,const TestParams & params)247 DepthBiasControlInstance (Context& context, const TestParams& params)
248 : vkt::TestInstance (context)
249 , m_params (params)
250 {}
~DepthBiasControlInstance(void)251 virtual ~DepthBiasControlInstance (void) {}
252
253 tcu::TestStatus iterate (void) override;
254
255 protected:
256 const TestParams m_params;
257 };
258
259 class DepthBiasControlCase : public vkt::TestCase
260 {
261 public:
262 static tcu::Vec4 kOutColor;
263
DepthBiasControlCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)264 DepthBiasControlCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
265 : vkt::TestCase (testCtx, name)
266 , m_params (params)
267 {}
~DepthBiasControlCase(void)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
274 protected:
275 const TestParams m_params;
276 };
277
278 tcu::Vec4 DepthBiasControlCase::kOutColor (0.0f, 0.0f, 1.0f, 1.0f);
279
checkSupport(Context & context) const280 void 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
createInstance(Context & context) const316 TestInstance* DepthBiasControlCase::createInstance (Context& context) const
317 {
318 return new DepthBiasControlInstance(context, m_params);
319 }
320
initPrograms(vk::SourceCollections & programCollection) const321 void 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
iterate(void)344 tcu::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
createDepthBiasControlTests(tcu::TestContext & testCtx)666 tcu::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