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 &params) : 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 &params)
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