xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawInvertedDepthRangesTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2017 Google Inc.
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 Inverted depth ranges tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawInvertedDepthRangesTests.hpp"
26 #include "vktDrawCreateInfoUtil.hpp"
27 #include "vktDrawImageObjectUtil.hpp"
28 #include "vktDrawBufferObjectUtil.hpp"
29 #include "vktTestGroupUtil.hpp"
30 #include "vktTestCaseUtil.hpp"
31 
32 #include "vkPrograms.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 
38 #include "tcuVector.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuTestLog.hpp"
42 
43 #include "deSharedPtr.hpp"
44 
45 #include <utility>
46 #include <array>
47 #include <vector>
48 #include <iterator>
49 
50 namespace vkt
51 {
52 namespace Draw
53 {
54 namespace
55 {
56 using namespace vk;
57 using de::MovePtr;
58 using de::SharedPtr;
59 using tcu::Vec4;
60 
61 struct TestParams
62 {
63     float minDepth;
64     float maxDepth;
65     VkBool32 depthClampEnable;
66     VkBool32 depthBiasEnable;
67     float depthBiasClamp;
68     const SharedGroupParams groupParams;
69 };
70 
71 constexpr uint32_t kImageDim  = 256u;
72 const VkExtent3D kImageExtent = makeExtent3D(kImageDim, kImageDim, 1u);
73 const Vec4 kClearColor(0.0f, 0.0f, 0.0f, 1.0f);
74 constexpr float kClearDepth   = 1.0f;
75 constexpr int kClearStencil   = 0;
76 constexpr int kMaskedStencil  = 1;
77 constexpr float kDepthEpsilon = 0.00025f; // Used to decide if a calculated depth passes the depth test.
78 constexpr float kDepthThreshold =
79     0.0064f; // Used when checking depth buffer values. Less than depth delta in each pixel (~= 1.4/205).
80 constexpr float kMargin         = 0.2f;     // Space between triangle and image border. See kVertices.
81 constexpr float kDiagonalMargin = 0.00125f; // Makes sure the image diagonal falls inside the triangle. See kVertices.
82 const Vec4 kVertexColor(0.0f, 0.5f, 0.5f, 1.0f); // Note: the first component will vary.
83 
84 // Maximum depth slope is constant for triangle and the value here is true only for triangle used it this tests.
85 constexpr float kMaxDepthSlope = 1.4f / 205;
86 
87 const std::array<Vec4, 3u> kVertices = {{
88     Vec4(-1.0f + kMargin, -1.0f + kMargin, -0.2f, 1.0f),                 //  0-----2
89     Vec4(-1.0f + kMargin, 1.0f - kMargin + kDiagonalMargin, 0.0f, 1.0f), //   |  /
90     Vec4(1.0f - kMargin + kDiagonalMargin, -1.0f + kMargin, 1.2f, 1.0f), //  1|/
91 }};
92 
93 class InvertedDepthRangesTestInstance : public TestInstance
94 {
95 public:
96     enum class ReferenceImageType
97     {
98         COLOR = 0,
99         DEPTH,
100     };
101 
102     using ColorAndDepth = std::pair<tcu::ConstPixelBufferAccess, tcu::ConstPixelBufferAccess>;
103 
104     InvertedDepthRangesTestInstance(Context &context, const TestParams &params);
105     tcu::TestStatus iterate(void);
106 
107     void preRenderCommands(VkCommandBuffer cmdBuffer, const VkClearValue &clearColor, const VkClearValue &clearDepth);
108     void draw(VkCommandBuffer cmdBuffer, const VkViewport &viewport);
109 
110     MovePtr<tcu::TextureLevel> generateReferenceImage(ReferenceImageType refType) const;
111 
112 #ifndef CTS_USES_VULKANSC
113     void beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u);
114     void beginRender(VkCommandBuffer cmdBuffer, const VkClearValue &clearColor, const VkClearValue &clearDepth,
115                      VkRenderingFlagsKHR renderingFlags = 0);
116 #endif // CTS_USES_VULKANSC
117 
118 private:
119     const TestParams m_params;
120     const VkFormat m_colorAttachmentFormat;
121     const VkFormat m_depthAttachmentFormat;
122     SharedPtr<Image> m_colorTargetImage;
123     Move<VkImageView> m_colorTargetView;
124     SharedPtr<Image> m_depthTargetImage;
125     Move<VkImageView> m_depthTargetView;
126     SharedPtr<Buffer> m_vertexBuffer;
127     Move<VkRenderPass> m_renderPass;
128     Move<VkFramebuffer> m_framebuffer;
129     Move<VkPipelineLayout> m_pipelineLayout;
130     Move<VkPipeline> m_pipeline;
131 };
132 
InvertedDepthRangesTestInstance(Context & context,const TestParams & params)133 InvertedDepthRangesTestInstance::InvertedDepthRangesTestInstance(Context &context, const TestParams &params)
134     : TestInstance(context)
135     , m_params(params)
136     , m_colorAttachmentFormat(VK_FORMAT_R8G8B8A8_UNORM)
137     , m_depthAttachmentFormat(VK_FORMAT_D16_UNORM)
138 {
139     const DeviceInterface &vk = m_context.getDeviceInterface();
140     const VkDevice device     = m_context.getDevice();
141     auto &alloc               = m_context.getDefaultAllocator();
142     auto qIndex               = m_context.getUniversalQueueFamilyIndex();
143 
144     // Vertex data
145     {
146         const auto dataSize = static_cast<VkDeviceSize>(kVertices.size() * sizeof(decltype(kVertices)::value_type));
147         m_vertexBuffer =
148             Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), alloc,
149                                    MemoryRequirement::HostVisible);
150 
151         deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), kVertices.data(), static_cast<size_t>(dataSize));
152         flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(),
153                                m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
154     }
155 
156     const VkImageUsageFlags targetImageUsageFlags =
157         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
158     const VkImageUsageFlags depthTargeUsageFlags =
159         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
160 
161     const ImageCreateInfo targetImageCreateInfo(VK_IMAGE_TYPE_2D,        // imageType,
162                                                 m_colorAttachmentFormat, // format,
163                                                 kImageExtent,            // extent,
164                                                 1u,                      // mipLevels,
165                                                 1u,                      // arrayLayers,
166                                                 VK_SAMPLE_COUNT_1_BIT,   // samples,
167                                                 VK_IMAGE_TILING_OPTIMAL, // tiling,
168                                                 targetImageUsageFlags);  // usage,
169 
170     m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, alloc, qIndex);
171 
172     const ImageCreateInfo depthTargetImageCreateInfo(VK_IMAGE_TYPE_2D,        // imageType,
173                                                      m_depthAttachmentFormat, // format,
174                                                      kImageExtent,            // extent,
175                                                      1u,                      // mipLevels,
176                                                      1u,                      // arrayLayers,
177                                                      VK_SAMPLE_COUNT_1_BIT,   // samples,
178                                                      VK_IMAGE_TILING_OPTIMAL, // tiling,
179                                                      depthTargeUsageFlags);   // usage,
180 
181     m_depthTargetImage = Image::createAndAlloc(vk, device, depthTargetImageCreateInfo, alloc, qIndex);
182 
183     const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D,
184                                                   m_colorAttachmentFormat);
185     m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
186 
187     const ImageViewCreateInfo depthTargetViewInfo(m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D,
188                                                   m_depthAttachmentFormat);
189     m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo);
190 
191     // Render pass and framebuffer
192     if (!m_params.groupParams->useDynamicRendering)
193     {
194         RenderPassCreateInfo renderPassCreateInfo;
195         renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,          // format
196                                                                  VK_SAMPLE_COUNT_1_BIT,            // samples
197                                                                  VK_ATTACHMENT_LOAD_OP_LOAD,       // loadOp
198                                                                  VK_ATTACHMENT_STORE_OP_STORE,     // storeOp
199                                                                  VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // stencilLoadOp
200                                                                  VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
201                                                                  VK_IMAGE_LAYOUT_GENERAL,          // initialLayout
202                                                                  VK_IMAGE_LAYOUT_GENERAL));        // finalLayout
203 
204         renderPassCreateInfo.addAttachment(AttachmentDescription(m_depthAttachmentFormat,          // format
205                                                                  VK_SAMPLE_COUNT_1_BIT,            // samples
206                                                                  VK_ATTACHMENT_LOAD_OP_LOAD,       // loadOp
207                                                                  VK_ATTACHMENT_STORE_OP_STORE,     // storeOp
208                                                                  VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // stencilLoadOp
209                                                                  VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
210                                                                  VK_IMAGE_LAYOUT_GENERAL,          // initialLayout
211                                                                  VK_IMAGE_LAYOUT_GENERAL));        // finalLayout
212 
213         const VkAttachmentReference colorAttachmentReference = {0u, VK_IMAGE_LAYOUT_GENERAL};
214 
215         const VkAttachmentReference depthAttachmentReference = {1u, VK_IMAGE_LAYOUT_GENERAL};
216 
217         renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
218                                                            (VkSubpassDescriptionFlags)0,    // flags
219                                                            0u,                              // inputAttachmentCount
220                                                            DE_NULL,                         // inputAttachments
221                                                            1u,                              // colorAttachmentCount
222                                                            &colorAttachmentReference,       // colorAttachments
223                                                            DE_NULL,                         // resolveAttachments
224                                                            depthAttachmentReference,        // depthStencilAttachment
225                                                            0u,                              // preserveAttachmentCount
226                                                            DE_NULL));                       // preserveAttachments
227 
228         m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
229 
230         std::vector<VkImageView> fbAttachments{*m_colorTargetView, *m_depthTargetView};
231 
232         const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, fbAttachments, kImageExtent.width,
233                                                           kImageExtent.height, 1u);
234         m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
235     }
236 
237     // Vertex input
238 
239     const VkVertexInputBindingDescription vertexInputBindingDescription = {
240         0u,                          // uint32_t             binding;
241         sizeof(Vec4),                // uint32_t             stride;
242         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate    inputRate;
243     };
244 
245     const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
246         0u,                            // uint32_t    location;
247         0u,                            // uint32_t    binding;
248         VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat    format;
249         0u                             // uint32_t    offset;
250     };
251 
252     const PipelineCreateInfo::VertexInputState vertexInputState =
253         PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 1, &vertexInputAttributeDescription);
254 
255     // Graphics pipeline
256 
257     const auto scissor = makeRect2D(kImageExtent);
258 
259     std::vector<VkDynamicState> dynamicStates;
260     dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
261 
262     const Unique<VkShaderModule> vertexModule(
263         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
264     const Unique<VkShaderModule> fragmentModule(
265         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
266 
267     const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
268     m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
269 
270     const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
271 
272     PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
273     pipelineCreateInfo.addShader(
274         PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
275     pipelineCreateInfo.addShader(
276         PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
277     pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
278     pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
279     pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendAttachmentState));
280     pipelineCreateInfo.addState(
281         PipelineCreateInfo::ViewportState(1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
282     pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true));
283     pipelineCreateInfo.addState(
284         PipelineCreateInfo::RasterizerState(m_params.depthClampEnable, // depthClampEnable
285                                             VK_FALSE,                  // rasterizerDiscardEnable
286                                             VK_POLYGON_MODE_FILL,      // polygonMode
287                                             VK_CULL_MODE_NONE,         // cullMode
288                                             VK_FRONT_FACE_CLOCKWISE,   // frontFace
289                                             m_params.depthBiasEnable,  // depthBiasEnable
290                                             0.0f,                      // depthBiasConstantFactor
291                                             m_params.depthBiasEnable ? m_params.depthBiasClamp : 0.0f, // depthBiasClamp
292                                             m_params.depthBiasEnable ? 1.0f : 0.0f, // depthBiasSlopeFactor
293                                             1.0f));                                 // lineWidth
294     pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
295     pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState(dynamicStates));
296 
297 #ifndef CTS_USES_VULKANSC
298     VkPipelineRenderingCreateInfoKHR renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
299                                                          DE_NULL,
300                                                          0u,
301                                                          1u,
302                                                          &m_colorAttachmentFormat,
303                                                          m_depthAttachmentFormat,
304                                                          VK_FORMAT_UNDEFINED};
305 
306     if (m_params.groupParams->useDynamicRendering)
307         pipelineCreateInfo.pNext = &renderingCreateInfo;
308 #endif // CTS_USES_VULKANSC
309 
310     m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
311 }
312 
preRenderCommands(VkCommandBuffer cmdBuffer,const VkClearValue & clearColor,const VkClearValue & clearDepth)313 void InvertedDepthRangesTestInstance::preRenderCommands(VkCommandBuffer cmdBuffer, const VkClearValue &clearColor,
314                                                         const VkClearValue &clearDepth)
315 {
316     const DeviceInterface &vk = m_context.getDeviceInterface();
317     const ImageSubresourceRange subresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
318     const ImageSubresourceRange depthSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT);
319 
320     initialTransitionColor2DImage(vk, cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
321                                   VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
322     initialTransitionDepth2DImage(vk, cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
323                                   VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
324     vk.cmdClearColorImage(cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1,
325                           &subresourceRange);
326     vk.cmdClearDepthStencilImage(cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
327                                  &clearDepth.depthStencil, 1u, &depthSubresourceRange);
328 
329     const VkMemoryBarrier memBarrier{
330         VK_STRUCTURE_TYPE_MEMORY_BARRIER,                                          // VkStructureType sType;
331         DE_NULL,                                                                   // const void* pNext;
332         VK_ACCESS_TRANSFER_WRITE_BIT,                                              // VkAccessFlags srcAccessMask;
333         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask;
334     };
335 
336     const VkMemoryBarrier depthBarrier{
337         VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
338         DE_NULL,                          // const void* pNext;
339         VK_ACCESS_TRANSFER_WRITE_BIT,     // VkAccessFlags srcAccessMask;
340         VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
341             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask;
342     };
343 
344     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
345                           1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
346     vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
347                           (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), 0,
348                           1, &depthBarrier, 0, DE_NULL, 0, DE_NULL);
349 }
350 
draw(VkCommandBuffer cmdBuffer,const VkViewport & viewport)351 void InvertedDepthRangesTestInstance::draw(VkCommandBuffer cmdBuffer, const VkViewport &viewport)
352 {
353     const DeviceInterface &vk = m_context.getDeviceInterface();
354     const VkBuffer buffer     = m_vertexBuffer->object();
355     const VkDeviceSize offset = 0;
356 
357     vk.cmdSetViewport(cmdBuffer, 0u, 1u, &viewport);
358     vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &buffer, &offset);
359     vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
360     vk.cmdDraw(cmdBuffer, 3, 1, 0, 0);
361 }
362 
generateReferenceImage(ReferenceImageType refType) const363 MovePtr<tcu::TextureLevel> InvertedDepthRangesTestInstance::generateReferenceImage(ReferenceImageType refType) const
364 {
365     const auto iWidth    = static_cast<int>(kImageExtent.width);
366     const auto iHeight   = static_cast<int>(kImageExtent.height);
367     const bool color     = (refType == ReferenceImageType::COLOR);
368     const auto tcuFormat = mapVkFormat(color ? m_colorAttachmentFormat : VK_FORMAT_D16_UNORM_S8_UINT);
369     MovePtr<tcu::TextureLevel> image(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
370     const tcu::PixelBufferAccess access(image->getAccess());
371     const float fImageDim    = static_cast<float>(kImageDim);
372     const float p1f          = fImageDim * kMargin / 2.0f;
373     const float p2f          = fImageDim * (2.0f - kMargin + kDiagonalMargin) / 2.0f;
374     const float triangleSide = fImageDim * (2.0f - (2.0f * kMargin - kDiagonalMargin)) / 2.0f;
375     const float clampMin     = de::min(m_params.minDepth, m_params.maxDepth);
376     const float clampMax     = de::max(m_params.minDepth, m_params.maxDepth);
377     std::array<float, 3> depthValues;
378     float depthBias = 0.0f;
379 
380     // Depth value of each vertex in kVertices.
381     DE_ASSERT(depthValues.size() == kVertices.size());
382     std::transform(begin(kVertices), end(kVertices), begin(depthValues), [](const Vec4 &coord) { return coord.z(); });
383 
384     if (color)
385         tcu::clear(access, kClearColor);
386     else
387     {
388         tcu::clearDepth(access, kClearDepth);
389         tcu::clearStencil(access, kClearStencil);
390 
391         if (m_params.depthBiasEnable)
392         {
393             const float depthBiasSlopeFactor = 1.0f;
394             const float r = 0.000030518f; // minimum resolvable difference is an implementation-dependent parameter
395             const float depthBiasConstantFactor =
396                 0.0f; // so we use factor 0.0 to not include it; same as in PipelineCreateInfo
397 
398             // Equations taken from vkCmdSetDepthBias manual page
399             depthBias = kMaxDepthSlope * depthBiasSlopeFactor + r * depthBiasConstantFactor;
400 
401             // dbclamp(x) function depends on the sign of the depthBiasClamp
402             if (m_params.depthBiasClamp < 0.0f)
403                 depthBias = de::max(depthBias, m_params.depthBiasClamp);
404             else if (m_params.depthBiasClamp > 0.0f)
405                 depthBias = de::min(depthBias, m_params.depthBiasClamp);
406 
407             if (m_params.maxDepth < m_params.minDepth)
408                 depthBias *= -1.0f;
409         }
410     }
411 
412     for (int y = 0; y < iHeight; ++y)
413         for (int x = 0; x < iWidth; ++x)
414         {
415             const float xcoord = static_cast<float>(x) + 0.5f;
416             const float ycoord = static_cast<float>(y) + 0.5f;
417 
418             if (xcoord < p1f || xcoord > p2f)
419                 continue;
420 
421             if (ycoord < p1f || ycoord > p2f)
422                 continue;
423 
424             if (ycoord > -xcoord + fImageDim)
425                 continue;
426 
427             // Interpolate depth value taking the 3 triangle corners into account.
428             const float b     = (ycoord - p1f) / triangleSide;
429             const float c     = (xcoord - p1f) / triangleSide;
430             const float a     = 1.0f - b - c;
431             const float depth = a * depthValues[0] + b * depthValues[1] + c * depthValues[2];
432 
433             // Depth values are always limited to the range [0,1] by clamping after depth bias addition is performed
434             const float depthClamped = de::clamp(depth + depthBias, 0.0f, 1.0f);
435             const float depthFinal   = depthClamped * m_params.maxDepth + (1.0f - depthClamped) * m_params.minDepth;
436             const float storedDepth =
437                 (m_params.depthClampEnable ? de::clamp(depthFinal, clampMin, clampMax) : depthFinal);
438 
439             if (m_params.depthClampEnable || de::inRange(depth, -kDepthEpsilon, 1.0f + kDepthEpsilon))
440             {
441                 if (color)
442                     access.setPixel(Vec4(depthFinal, kVertexColor.y(), kVertexColor.z(), kVertexColor.w()), x, y);
443                 else
444                 {
445                     if (!m_params.depthClampEnable && (de::inRange(depth, -kDepthEpsilon, kDepthEpsilon) ||
446                                                        de::inRange(depth, 1.0f - kDepthEpsilon, 1.0f + kDepthEpsilon)))
447                     {
448                         // We should avoid comparing this pixel due to possible rounding problems.
449                         // Pixels that should not be compared will be marked in the stencil aspect.
450                         access.setPixStencil(kMaskedStencil, x, y);
451                     }
452                     access.setPixDepth(storedDepth, x, y);
453                 }
454             }
455         }
456 
457     return image;
458 }
459 
460 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkRenderingFlagsKHR renderingFlags)461 void InvertedDepthRangesTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,
462                                                               VkRenderingFlagsKHR renderingFlags)
463 {
464     VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
465         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
466         DE_NULL,                                                         // const void* pNext;
467         renderingFlags,                                                  // VkRenderingFlagsKHR flags;
468         0u,                                                              // uint32_t viewMask;
469         1u,                                                              // uint32_t colorAttachmentCount;
470         &m_colorAttachmentFormat,                                        // const VkFormat* pColorAttachmentFormats;
471         m_depthAttachmentFormat,                                         // VkFormat depthAttachmentFormat;
472         VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
473         VK_SAMPLE_COUNT_1_BIT,                                           // VkSampleCountFlagBits rasterizationSamples;
474     };
475     const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
476 
477     VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
478     if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
479         usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
480 
481     const VkCommandBufferBeginInfo commandBufBeginParams{
482         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
483         DE_NULL,                                     // const void* pNext;
484         usageFlags,                                  // VkCommandBufferUsageFlags flags;
485         &bufferInheritanceInfo};
486 
487     const DeviceInterface &vk = m_context.getDeviceInterface();
488     VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
489 }
490 
beginRender(VkCommandBuffer cmdBuffer,const VkClearValue & clearColor,const VkClearValue & clearDepth,VkRenderingFlagsKHR renderingFlags)491 void InvertedDepthRangesTestInstance::beginRender(VkCommandBuffer cmdBuffer, const VkClearValue &clearColor,
492                                                   const VkClearValue &clearDepth, VkRenderingFlagsKHR renderingFlags)
493 {
494     const DeviceInterface &vk = m_context.getDeviceInterface();
495 
496     beginRendering(vk, cmdBuffer, *m_colorTargetView, *m_depthTargetView, false, makeRect2D(kImageExtent), clearColor,
497                    clearDepth, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD,
498                    renderingFlags);
499 }
500 #endif // CTS_USES_VULKANSC
501 
iterate(void)502 tcu::TestStatus InvertedDepthRangesTestInstance::iterate(void)
503 {
504     // Set up the viewport and draw
505 
506     const VkViewport viewport{
507         0.0f,                                    // float    x;
508         0.0f,                                    // float    y;
509         static_cast<float>(kImageExtent.width),  // float    width;
510         static_cast<float>(kImageExtent.height), // float    height;
511         m_params.minDepth,                       // float    minDepth;
512         m_params.maxDepth,                       // float    maxDepth;
513     };
514 
515     const DeviceInterface &vk       = m_context.getDeviceInterface();
516     const VkDevice device           = m_context.getDevice();
517     const VkQueue queue             = m_context.getUniversalQueue();
518     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
519     auto &alloc                     = m_context.getDefaultAllocator();
520     const VkClearValue clearColor   = makeClearValueColor(kClearColor);
521     const VkClearValue clearDepth   = makeClearValueDepthStencil(kClearDepth, 0u);
522 
523     // Command buffer
524 
525     const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
526     const Unique<VkCommandPool> cmdPool(createCommandPool(vk, device, &cmdPoolCreateInfo));
527     const Unique<VkCommandBuffer> cmdBuffer(
528         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
529     Move<VkCommandBuffer> secCmdBuffer;
530 
531 #ifndef CTS_USES_VULKANSC
532     if (m_params.groupParams->useSecondaryCmdBuffer)
533     {
534         secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
535 
536         // record secondary command buffer
537         if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
538         {
539             beginSecondaryCmdBuffer(*secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
540             beginRender(*secCmdBuffer, clearColor, clearDepth);
541         }
542         else
543             beginSecondaryCmdBuffer(*secCmdBuffer);
544 
545         draw(*secCmdBuffer, viewport);
546 
547         if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
548             endRendering(vk, *secCmdBuffer);
549 
550         endCommandBuffer(vk, *secCmdBuffer);
551 
552         // record primary command buffer
553         beginCommandBuffer(vk, *cmdBuffer, 0u);
554 
555         preRenderCommands(*cmdBuffer, clearColor, clearDepth);
556 
557         if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
558             beginRender(*cmdBuffer, clearColor, clearDepth, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
559 
560         vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
561 
562         if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
563             endRendering(vk, *cmdBuffer);
564 
565         endCommandBuffer(vk, *cmdBuffer);
566     }
567     else if (m_params.groupParams->useDynamicRendering)
568     {
569         beginCommandBuffer(vk, *cmdBuffer);
570 
571         preRenderCommands(*cmdBuffer, clearColor, clearDepth);
572         beginRender(*cmdBuffer, clearColor, clearDepth);
573         draw(*cmdBuffer, viewport);
574         endRendering(vk, *cmdBuffer);
575 
576         endCommandBuffer(vk, *cmdBuffer);
577     }
578 #endif // CTS_USES_VULKANSC
579 
580     if (!m_params.groupParams->useDynamicRendering)
581     {
582         beginCommandBuffer(vk, *cmdBuffer);
583 
584         preRenderCommands(*cmdBuffer, clearColor, clearDepth);
585         beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(kImageExtent));
586         draw(*cmdBuffer, viewport);
587         endRenderPass(vk, *cmdBuffer);
588 
589         endCommandBuffer(vk, *cmdBuffer);
590     }
591 
592     // Submit
593     submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
594 
595     // Get result
596     const auto zeroOffset  = makeOffset3D(0, 0, 0);
597     const auto iWidth      = static_cast<int>(kImageExtent.width);
598     const auto iHeight     = static_cast<int>(kImageExtent.height);
599     const auto colorPixels = m_colorTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth,
600                                                              iHeight, VK_IMAGE_ASPECT_COLOR_BIT);
601     const auto depthPixels = m_depthTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth,
602                                                              iHeight, VK_IMAGE_ASPECT_DEPTH_BIT);
603     ColorAndDepth results(colorPixels, depthPixels);
604 
605     auto &resultImage = results.first;
606     auto &resultDepth = results.second;
607 
608     // Verify results
609     auto &log           = m_context.getTestContext().getLog();
610     auto referenceImage = generateReferenceImage(ReferenceImageType::COLOR);
611     auto referenceDepth = generateReferenceImage(ReferenceImageType::DEPTH);
612 
613     bool fail = false;
614     // Color aspect.
615     if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f,
616                            tcu::COMPARE_LOG_RESULT))
617         fail = true;
618 
619     // Depth aspect.
620     bool depthFail = false;
621 
622     const auto refWidth  = referenceDepth->getWidth();
623     const auto refHeight = referenceDepth->getHeight();
624     const auto refAccess = referenceDepth->getAccess();
625 
626     tcu::TextureLevel errorMask(mapVkFormat(VK_FORMAT_R8G8B8_UNORM), refWidth, refHeight);
627     auto errorAccess = errorMask.getAccess();
628     const tcu::Vec4 kGreen(0.0f, 1.0f, 0.0f, 1.0f);
629     const tcu::Vec4 kRed(1.0f, 0.0f, 0.0f, 1.0f);
630 
631     tcu::clear(errorAccess, kGreen);
632 
633     for (int y = 0; y < refHeight; ++y)
634         for (int x = 0; x < refWidth; ++x)
635         {
636             // Ignore pixels that could be too close to having or not having coverage.
637             const auto stencil = refAccess.getPixStencil(x, y);
638             if (stencil == kMaskedStencil)
639                 continue;
640 
641             // Compare the rest using a known threshold.
642             const auto refValue = refAccess.getPixDepth(x, y);
643             const auto resValue = resultDepth.getPixDepth(x, y);
644             if (!de::inRange(resValue, refValue - kDepthThreshold, refValue + kDepthThreshold))
645             {
646                 depthFail = true;
647                 errorAccess.setPixel(kRed, x, y);
648             }
649         }
650 
651     if (depthFail)
652     {
653         log << tcu::TestLog::Message << "Depth Image comparison failed" << tcu::TestLog::EndMessage;
654         log << tcu::TestLog::Image("Result", "Result", resultDepth)
655             << tcu::TestLog::Image("Reference", "Reference", refAccess)
656             << tcu::TestLog::Image("ErrorMask", "Error mask", errorAccess);
657     }
658 
659     if (fail || depthFail)
660         return tcu::TestStatus::fail("Result images are incorrect");
661 
662     return tcu::TestStatus::pass("Pass");
663 }
664 
665 class InvertedDepthRangesTest : public TestCase
666 {
667 public:
InvertedDepthRangesTest(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)668     InvertedDepthRangesTest(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
669         : TestCase(testCtx, name)
670         , m_params(params)
671     {
672     }
673 
initPrograms(SourceCollections & programCollection) const674     void initPrograms(SourceCollections &programCollection) const
675     {
676         // Vertex shader
677         {
678             std::ostringstream src;
679             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
680                 << "\n"
681                 << "layout(location = 0) in highp vec4 in_position;\n"
682                 << "\n"
683                 << "out gl_PerVertex {\n"
684                 << "    highp vec4 gl_Position;\n"
685                 << "};\n"
686                 << "\n"
687                 << "void main(void)\n"
688                 << "{\n"
689                 << "    gl_Position = in_position;\n"
690                 << "}\n";
691 
692             programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
693         }
694 
695         // Fragment shader
696         {
697             std::ostringstream src;
698             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
699                 << "\n"
700                 << "layout(location = 0) out highp vec4 out_color;\n"
701                 << "\n"
702                 << "void main(void)\n"
703                 << "{\n"
704                 << "    out_color = vec4(gl_FragCoord.z, " << kVertexColor.y() << ", " << kVertexColor.z() << ", "
705                 << kVertexColor.w() << ");\n"
706                 << "}\n";
707 
708             programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
709         }
710     }
711 
checkSupport(Context & context) const712     virtual void checkSupport(Context &context) const
713     {
714         if (m_params.depthClampEnable)
715             context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_CLAMP);
716 
717         if (m_params.depthBiasEnable && m_params.depthBiasClamp != 0.0f)
718             context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_BIAS_CLAMP);
719 
720         if (m_params.minDepth > 1.0f || m_params.minDepth < 0.0f || m_params.maxDepth > 1.0f ||
721             m_params.maxDepth < 0.0f)
722             context.requireDeviceFunctionality("VK_EXT_depth_range_unrestricted");
723 
724         if (m_params.groupParams->useDynamicRendering)
725             context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
726     }
727 
createInstance(Context & context) const728     virtual TestInstance *createInstance(Context &context) const
729     {
730         return new InvertedDepthRangesTestInstance(context, m_params);
731     }
732 
733 private:
734     const TestParams m_params;
735 };
736 
populateTestGroup(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)737 void populateTestGroup(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
738 {
739     const struct
740     {
741         std::string name;
742         VkBool32 depthClamp;
743     } depthClamp[] = {
744         {"depthclamp", VK_TRUE},
745         {"nodepthclamp", VK_FALSE},
746     };
747 
748     const struct
749     {
750         std::string name;
751         float delta;
752         VkBool32 depthBiasEnable;
753         float depthBiasClamp;
754     } depthParams[] = {
755         {"deltazero", 0.0f, false, 0.0f},
756         {"deltasmall", 0.3f, false, 0.0f},
757         {"deltaone", 1.0f, false, 0.0f},
758 
759         // depthBiasClamp must be smaller then maximum depth slope to make a difference
760         {"deltaone_bias_clamp_neg", 1.0f, true, -0.003f},
761         {"deltasmall_bias_clamp_pos", 0.3f, true, 0.003f},
762 
763         // Range > 1.0 requires VK_EXT_depth_range_unrestricted extension
764         {"depth_range_unrestricted", 2.7f, false, 0.0f},
765     };
766 
767     for (int ndxDepthClamp = 0; ndxDepthClamp < DE_LENGTH_OF_ARRAY(depthClamp); ++ndxDepthClamp)
768         for (int ndxParams = 0; ndxParams < DE_LENGTH_OF_ARRAY(depthParams); ++ndxParams)
769         {
770             const auto &cDepthClamp  = depthClamp[ndxDepthClamp];
771             const auto &cDepthParams = depthParams[ndxParams];
772             const float minDepth     = 0.5f + cDepthParams.delta / 2.0f;
773             const float maxDepth     = minDepth - cDepthParams.delta;
774             DE_ASSERT(minDepth >= maxDepth);
775 
776             const TestParams params{
777                 minDepth,   maxDepth, cDepthClamp.depthClamp, cDepthParams.depthBiasEnable, cDepthParams.depthBiasClamp,
778                 groupParams};
779 
780             std::string name = cDepthClamp.name + "_" + cDepthParams.name;
781             testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name, params));
782         }
783 }
784 
785 } // namespace
786 
createInvertedDepthRangesTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)787 tcu::TestCaseGroup *createInvertedDepthRangesTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
788 {
789     return createTestGroup(testCtx, "inverted_depth_ranges", populateTestGroup, groupParams);
790 }
791 
792 } // namespace Draw
793 } // namespace vkt
794