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