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 namespace vkt
45 {
46 namespace Draw
47 {
48 namespace
49 {
50 using namespace vk;
51 using tcu::Vec4;
52 using de::SharedPtr;
53 using de::MovePtr;
54
55 struct TestParams
56 {
57 VkBool32 depthClampEnable;
58 float minDepth;
59 float maxDepth;
60 };
61
62 class InvertedDepthRangesTestInstance : public TestInstance
63 {
64 public:
65 InvertedDepthRangesTestInstance (Context& context, const TestParams& params);
66 tcu::TestStatus iterate (void);
67 tcu::ConstPixelBufferAccess draw (const VkViewport viewport);
68 MovePtr<tcu::TextureLevel> generateReferenceImage (void) const;
69
70 private:
71 const TestParams m_params;
72 const VkFormat m_colorAttachmentFormat;
73 SharedPtr<Image> m_colorTargetImage;
74 Move<VkImageView> m_colorTargetView;
75 SharedPtr<Buffer> m_vertexBuffer;
76 Move<VkRenderPass> m_renderPass;
77 Move<VkFramebuffer> m_framebuffer;
78 Move<VkPipelineLayout> m_pipelineLayout;
79 Move<VkPipeline> m_pipeline;
80 };
81
InvertedDepthRangesTestInstance(Context & context,const TestParams & params)82 InvertedDepthRangesTestInstance::InvertedDepthRangesTestInstance (Context& context, const TestParams& params)
83 : TestInstance (context)
84 , m_params (params)
85 , m_colorAttachmentFormat (VK_FORMAT_R8G8B8A8_UNORM)
86 {
87 const DeviceInterface& vk = m_context.getDeviceInterface();
88 const VkDevice device = m_context.getDevice();
89
90 if (m_params.depthClampEnable && !m_context.getDeviceFeatures().depthClamp)
91 TCU_THROW(NotSupportedError, "DepthClamp device feature not supported.");
92
93 if (params.minDepth > 1.0f ||
94 params.minDepth < 0.0f ||
95 params.maxDepth > 1.0f ||
96 params.maxDepth < 0.0f)
97 {
98 if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_EXT_depth_range_unrestricted"))
99 throw tcu::NotSupportedError("Test variant with minDepth/maxDepth outside 0..1 requires the VK_EXT_depth_range_unrestricted extension");
100 }
101
102 // Vertex data
103 {
104 std::vector<Vec4> vertexData;
105
106 vertexData.push_back(Vec4(-0.8f, -0.8f, -0.2f, 1.0f)); // 0-----2
107 vertexData.push_back(Vec4(-0.8f, 0.8f, 0.0f, 1.0f)); // | /
108 vertexData.push_back(Vec4( 0.8f, -0.8f, 1.2f, 1.0f)); // 1|/
109
110 const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
111 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
112 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
113
114 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
115 flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
116 }
117
118 // Render pass
119 {
120 const VkExtent3D targetImageExtent = { 256, 256, 1 };
121 const VkImageUsageFlags targetImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
122
123 const ImageCreateInfo targetImageCreateInfo(
124 VK_IMAGE_TYPE_2D, // imageType,
125 m_colorAttachmentFormat, // format,
126 targetImageExtent, // extent,
127 1u, // mipLevels,
128 1u, // arrayLayers,
129 VK_SAMPLE_COUNT_1_BIT, // samples,
130 VK_IMAGE_TILING_OPTIMAL, // tiling,
131 targetImageUsageFlags); // usage,
132
133 m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
134
135 RenderPassCreateInfo renderPassCreateInfo;
136 renderPassCreateInfo.addAttachment(AttachmentDescription(
137 m_colorAttachmentFormat, // format
138 VK_SAMPLE_COUNT_1_BIT, // samples
139 VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp
140 VK_ATTACHMENT_STORE_OP_STORE, // storeOp
141 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
142 VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
143 VK_IMAGE_LAYOUT_GENERAL, // initialLayout
144 VK_IMAGE_LAYOUT_GENERAL)); // finalLayout
145
146 const VkAttachmentReference colorAttachmentReference =
147 {
148 0u,
149 VK_IMAGE_LAYOUT_GENERAL
150 };
151
152 renderPassCreateInfo.addSubpass(SubpassDescription(
153 VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
154 (VkSubpassDescriptionFlags)0, // flags
155 0u, // inputAttachmentCount
156 DE_NULL, // inputAttachments
157 1u, // colorAttachmentCount
158 &colorAttachmentReference, // colorAttachments
159 DE_NULL, // resolveAttachments
160 AttachmentReference(), // depthStencilAttachment
161 0u, // preserveAttachmentCount
162 DE_NULL)); // preserveAttachments
163
164 m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
165 }
166
167 // Framebuffer
168 {
169 const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
170 m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
171
172 std::vector<VkImageView> colorAttachments(1);
173 colorAttachments[0] = *m_colorTargetView;
174
175 const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, 256, 256, 1);
176 m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
177 }
178
179 // Vertex input
180
181 const VkVertexInputBindingDescription vertexInputBindingDescription =
182 {
183 0u, // uint32_t binding;
184 sizeof(Vec4), // uint32_t stride;
185 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
186 };
187
188 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
189 {
190 0u, // uint32_t location;
191 0u, // uint32_t binding;
192 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
193 0u // uint32_t offset;
194 };
195
196 const PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
197 1, &vertexInputAttributeDescription);
198
199 // Graphics pipeline
200
201 const VkRect2D scissor = makeRect2D(256u, 256u);
202
203 std::vector<VkDynamicState> dynamicStates;
204 dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
205
206 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
207 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
208
209 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
210 m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
211
212 const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
213
214 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
215 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
216 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
217 pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState));
218 pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
219 pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState (1, &colorBlendAttachmentState));
220 pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
221 pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState ());
222 pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState (
223 m_params.depthClampEnable, // depthClampEnable
224 VK_FALSE, // rasterizerDiscardEnable
225 VK_POLYGON_MODE_FILL, // polygonMode
226 VK_CULL_MODE_NONE, // cullMode
227 VK_FRONT_FACE_CLOCKWISE, // frontFace
228 VK_FALSE, // depthBiasEnable
229 0.0f, // depthBiasConstantFactor
230 0.0f, // depthBiasClamp
231 0.0f, // depthBiasSlopeFactor
232 1.0f)); // lineWidth
233 pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ());
234 pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState (dynamicStates));
235
236 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
237 }
238
draw(const VkViewport viewport)239 tcu::ConstPixelBufferAccess InvertedDepthRangesTestInstance::draw (const VkViewport viewport)
240 {
241 const DeviceInterface& vk = m_context.getDeviceInterface();
242 const VkDevice device = m_context.getDevice();
243 const VkQueue queue = m_context.getUniversalQueue();
244 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
245
246 // Command buffer
247
248 const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex);
249 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo));
250 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
251
252 // Draw
253
254 beginCommandBuffer(vk, *cmdBuffer);
255
256 vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport);
257
258 {
259 const VkClearColorValue clearColor = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f).color;
260 const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
261
262 initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
263 vk.cmdClearColorImage(*cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
264 }
265 {
266 const VkMemoryBarrier memBarrier =
267 {
268 VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
269 DE_NULL, // const void* pNext;
270 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
271 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask;
272 };
273
274 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
275 }
276
277 beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, 256u, 256u));
278
279 {
280 const VkDeviceSize offset = 0;
281 const VkBuffer buffer = m_vertexBuffer->object();
282
283 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
284 }
285
286 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
287 vk.cmdDraw(*cmdBuffer, 3, 1, 0, 0);
288 endRenderPass(vk, *cmdBuffer);
289 endCommandBuffer(vk, *cmdBuffer);
290
291 // Submit
292 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
293
294 // Get result
295 {
296 const VkOffset3D zeroOffset = { 0, 0, 0 };
297 return m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, 256, 256, VK_IMAGE_ASPECT_COLOR_BIT);
298 }
299 }
300
generateReferenceImage(void) const301 MovePtr<tcu::TextureLevel> InvertedDepthRangesTestInstance::generateReferenceImage (void) const
302 {
303 MovePtr<tcu::TextureLevel> image (new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), 256, 256));
304 const tcu::PixelBufferAccess access (image->getAccess());
305 const Vec4 black (0.0f, 0.0f, 0.0f, 1.0f);
306 const int p1 = static_cast<int>(256.0f * 0.2f / 2.0f);
307 const int p2 = static_cast<int>(256.0f * 1.8f / 2.0f);
308 const float delta = 256.0f * 1.6f / 2.0f;
309 const float depthValues[] = { -0.2f, 0.0f, 1.2f };
310
311 tcu::clear(access, black);
312
313 for (int y = p1; y <= p2; ++y)
314 for (int x = p1; x < 256 - y; ++x)
315 {
316 const float a = static_cast<float>(p2 - x + p1 - y) / delta;
317 const float b = static_cast<float>(y - p1) / delta;
318 const float c = 1.0f - a - b;
319 const float depth = a * depthValues[0] + b * depthValues[1] + c * depthValues[2];
320 const float depthClamped = de::clamp(depth, 0.0f, 1.0f);
321 const float depthFinal = depthClamped * m_params.maxDepth + (1.0f - depthClamped) * m_params.minDepth;
322
323 if (m_params.depthClampEnable || (depth >= 0.0f && depth <= 1.0f))
324 access.setPixel(Vec4(depthFinal, 0.5f, 0.5f, 1.0f), x, y);
325 }
326
327 return image;
328 }
329
iterate(void)330 tcu::TestStatus InvertedDepthRangesTestInstance::iterate (void)
331 {
332 // Set up the viewport and draw
333
334 const VkViewport viewport =
335 {
336 0.0f, // float x;
337 0.0f, // float y;
338 256.0f, // float width;
339 256.0f, // float height;
340 m_params.minDepth, // float minDepth;
341 m_params.maxDepth, // float maxDepth;
342 };
343
344 const tcu::ConstPixelBufferAccess resultImage = draw(viewport);
345
346 // Verify the results
347
348 tcu::TestLog& log = m_context.getTestContext().getLog();
349 MovePtr<tcu::TextureLevel> referenceImage = generateReferenceImage();
350
351 if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
352 return tcu::TestStatus::fail("Rendered image is incorrect");
353 else
354 return tcu::TestStatus::pass("Pass");
355 }
356
357 class InvertedDepthRangesTest : public TestCase
358 {
359 public:
InvertedDepthRangesTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)360 InvertedDepthRangesTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
361 : TestCase (testCtx, name, description)
362 , m_params (params)
363 {
364 }
365
initPrograms(SourceCollections & programCollection) const366 void initPrograms (SourceCollections& programCollection) const
367 {
368 // Vertex shader
369 {
370 std::ostringstream src;
371 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
372 << "\n"
373 << "layout(location = 0) in vec4 in_position;\n"
374 << "\n"
375 << "out gl_PerVertex {\n"
376 << " vec4 gl_Position;\n"
377 << "};\n"
378 << "\n"
379 << "void main(void)\n"
380 << "{\n"
381 << " gl_Position = in_position;\n"
382 << "}\n";
383
384 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
385 }
386
387 // Fragment shader
388 {
389 std::ostringstream src;
390 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
391 << "\n"
392 << "layout(location = 0) out vec4 out_color;\n"
393 << "\n"
394 << "void main(void)\n"
395 << "{\n"
396 << " out_color = vec4(gl_FragCoord.z, 0.5, 0.5, 1.0);\n"
397 << "}\n";
398
399 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
400 }
401 }
402
createInstance(Context & context) const403 virtual TestInstance* createInstance (Context& context) const
404 {
405 return new InvertedDepthRangesTestInstance(context, m_params);
406 }
407
408 private:
409 const TestParams m_params;
410 };
411
populateTestGroup(tcu::TestCaseGroup * testGroup)412 void populateTestGroup (tcu::TestCaseGroup* testGroup)
413 {
414 const struct
415 {
416 const char* const name;
417 VkBool32 depthClamp;
418 } depthClamp[] =
419 {
420 { "depthclamp", VK_TRUE },
421 { "nodepthclamp", VK_FALSE },
422 };
423
424 const struct
425 {
426 const char* const name;
427 float delta;
428 } delta[] =
429 {
430 { "deltazero", 0.0f },
431 { "deltasmall", 0.3f },
432 { "deltaone", 1.0f },
433
434 // Range > 1.0 requires VK_EXT_depth_range_unrestricted extension
435 { "depth_range_unrestricted", 2.7f },
436 };
437
438 for (int ndxDepthClamp = 0; ndxDepthClamp < DE_LENGTH_OF_ARRAY(depthClamp); ++ndxDepthClamp)
439 for (int ndxDelta = 0; ndxDelta < DE_LENGTH_OF_ARRAY(delta); ++ndxDelta)
440 {
441 const float minDepth = 0.5f + delta[ndxDelta].delta / 2.0f;
442 const float maxDepth = minDepth - delta[ndxDelta].delta;
443 DE_ASSERT(minDepth >= maxDepth);
444
445 const TestParams params =
446 {
447 depthClamp[ndxDepthClamp].depthClamp,
448 minDepth,
449 maxDepth
450 };
451 std::ostringstream name;
452 name << depthClamp[ndxDepthClamp].name << "_" << delta[ndxDelta].name;
453
454 testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name.str(), "", params));
455 }
456 }
457
458 } // anonymous
459
createInvertedDepthRangesTests(tcu::TestContext & testCtx)460 tcu::TestCaseGroup* createInvertedDepthRangesTests (tcu::TestContext& testCtx)
461 {
462 return createTestGroup(testCtx, "inverted_depth_ranges", "Inverted depth ranges", populateTestGroup);
463 }
464
465 } // Draw
466 } // vkt
467