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 ¶ms);
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 ¶ms)
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 ¶ms)
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