1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Test for conditional rendering with commands that ignore conditions
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktConditionalIgnoreTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
27
28 #include "vktTestCase.hpp"
29 #include "vkPrograms.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vktTestCaseUtil.hpp"
32 #include "vkImageWithMemory.hpp"
33
34 #include "vktTestCase.hpp"
35
36 #include "vkDefs.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkObjUtil.hpp"
40 #include "vkBufferWithMemory.hpp"
41 #include "vkImageWithMemory.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkCmdUtil.hpp"
44 #include "vkImageUtil.hpp"
45 #include "vkBarrierUtil.hpp"
46
47 #include "tcuImageCompare.hpp"
48 #include "tcuDefs.hpp"
49 #include "tcuTextureUtil.hpp"
50 #include "tcuTestLog.hpp"
51
52 #include <vector>
53 #include <sstream>
54 #include <algorithm>
55 #include <utility>
56 #include <iterator>
57 #include <string>
58 #include <limits>
59 #include <memory>
60 #include <functional>
61 #include <cstddef>
62 #include <set>
63
64 namespace vkt
65 {
66 namespace conditional
67 {
68 namespace
69 {
70
71 using namespace vk;
72
73 class ConditionalIgnoreClearTestCase : public vkt::TestCase
74 {
75 public:
76 ConditionalIgnoreClearTestCase(tcu::TestContext &context, const std::string &name, const ConditionalData &data);
initPrograms(SourceCollections &) const77 void initPrograms(SourceCollections &) const override
78 {
79 }
80 TestInstance *createInstance(Context &context) const override;
checkSupport(Context & context) const81 void checkSupport(Context &context) const override
82 {
83 context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
84 if (m_data.conditionInherited && !context.getConditionalRenderingFeaturesEXT().inheritedConditionalRendering)
85 TCU_THROW(NotSupportedError, "Device does not support inherited conditional rendering");
86 }
87
88 private:
89 const ConditionalData m_data;
90 };
91
92 class ConditionalIgnoreClearTestInstance : public vkt::TestInstance
93 {
94 public:
ConditionalIgnoreClearTestInstance(Context & context,const ConditionalData & data)95 ConditionalIgnoreClearTestInstance(Context &context, const ConditionalData &data)
96 : vkt::TestInstance(context)
97 , m_data(data){};
98 virtual tcu::TestStatus iterate(void);
99
100 private:
101 const ConditionalData m_data;
102 };
103
ConditionalIgnoreClearTestCase(tcu::TestContext & context,const std::string & name,const ConditionalData & data)104 ConditionalIgnoreClearTestCase::ConditionalIgnoreClearTestCase(tcu::TestContext &context, const std::string &name,
105 const ConditionalData &data)
106 : vkt::TestCase(context, name)
107 , m_data(data)
108 {
109 }
110
createInstance(Context & context) const111 TestInstance *ConditionalIgnoreClearTestCase::createInstance(Context &context) const
112 {
113 return new ConditionalIgnoreClearTestInstance(context, m_data);
114 }
115
116 //make a buffer to read an image back after rendering
makeBufferForImage(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,VkFormat imageFormat,VkExtent3D imageExtent)117 std::unique_ptr<BufferWithMemory> makeBufferForImage(const DeviceInterface &vkd, const VkDevice device,
118 Allocator &allocator, VkFormat imageFormat, VkExtent3D imageExtent)
119 {
120 const auto tcuFormat = mapVkFormat(imageFormat);
121 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) *
122 imageExtent.width * imageExtent.height);
123 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
124 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
125
126 auto outBuffer = std::unique_ptr<BufferWithMemory>(
127 new BufferWithMemory(vkd, device, allocator, outBufferInfo, MemoryRequirement::HostVisible));
128
129 return outBuffer;
130 }
131
iterate(void)132 tcu::TestStatus ConditionalIgnoreClearTestInstance::iterate(void)
133 {
134 const auto &vkd = m_context.getDeviceInterface();
135 const auto device = m_context.getDevice();
136 auto &alloc = m_context.getDefaultAllocator();
137 const auto imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
138 const auto depthFormat = VK_FORMAT_D16_UNORM;
139 const auto imageExtent = makeExtent3D(2, 2, 1u);
140 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
141
142 const auto expected = tcu::Vec4(0.0, 0.0, 0.0, 1.0);
143
144 const VkClearColorValue clearColor = {{0.0, 0.0, 0.0, 1.0}};
145 const VkClearColorValue clearColorWrong = {{1.0, 0.0, 0.0, 1.0}};
146
147 const VkClearDepthStencilValue depthClear = {0.0, 0};
148 const VkClearDepthStencilValue depthClearWrong = {1.0, 0};
149
150 const tcu::IVec3 imageDim(static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height),
151 static_cast<int>(imageExtent.depth));
152 const tcu::IVec2 imageSize(imageDim.x(), imageDim.y());
153
154 de::MovePtr<ImageWithMemory> colorAttachment;
155 de::MovePtr<ImageWithMemory> depthAttachment;
156
157 //create color image
158 const auto imageUsage = static_cast<VkImageUsageFlags>(
159 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
160 const VkImageCreateInfo imageCreateInfo = {
161 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
162 nullptr, // const void* pNext;
163 0u, // VkImageCreateFlags flags;
164 VK_IMAGE_TYPE_2D, // VkImageType imageType;
165 imageFormat, // VkFormat format;
166 imageExtent, // VkExtent3D extent;
167 1u, // uint32_t mipLevels;
168 1u, // uint32_t arrayLayers;
169 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
170 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
171 imageUsage, // VkImageUsageFlags usage;
172 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
173 0, // uint32_t queueFamilyIndexCount;
174 nullptr, // const uint32_t* pQueueFamilyIndices;
175 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
176 };
177
178 const auto colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
179 colorAttachment =
180 de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
181 auto colorAttachmentView =
182 makeImageView(vkd, device, colorAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSubresourceRange);
183
184 //create depth image
185 const auto depthImageUsage =
186 static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
187 VK_IMAGE_USAGE_TRANSFER_DST_BIT);
188 const VkImageCreateInfo depthImageCreateInfo = {
189 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
190 nullptr, // const void* pNext;
191 0u, // VkImageCreateFlags flags;
192 VK_IMAGE_TYPE_2D, // VkImageType imageType;
193 depthFormat, // VkFormat format;
194 imageExtent, // VkExtent3D extent;
195 1u, // uint32_t mipLevels;
196 1u, // uint32_t arrayLayers;
197 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
198 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
199 depthImageUsage, // VkImageUsageFlags usage;
200 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
201 0u, // uint32_t queueFamilyIndexCount;
202 nullptr, // const uint32_t* pQueueFamilyIndices;
203 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
204 };
205
206 const auto depthSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
207 depthAttachment = de::MovePtr<ImageWithMemory>(
208 new ImageWithMemory(vkd, device, alloc, depthImageCreateInfo, MemoryRequirement::Any));
209 auto depthAttachmentView =
210 makeImageView(vkd, device, depthAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, depthFormat, depthSubresourceRange);
211
212 //buffers to read the outputs
213 const auto outBuffer = makeBufferForImage(vkd, device, alloc, imageFormat, imageExtent);
214 const auto &outBufferAlloc = outBuffer->getAllocation();
215 const void *outBufferData = outBufferAlloc.getHostPtr();
216
217 const auto outDepthBuffer = makeBufferForImage(vkd, device, alloc, depthFormat, imageExtent);
218 const auto &outDepthBufferAlloc = outDepthBuffer->getAllocation();
219 const void *outDepthBufferData = outDepthBufferAlloc.getHostPtr();
220
221 const auto commandPool = createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, qIndex);
222 auto commandBuffer = allocateCommandBuffer(vkd, device, commandPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
223 auto commandBuffer2 = allocateCommandBuffer(vkd, device, commandPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
224 auto commandBuffer3 = allocateCommandBuffer(vkd, device, commandPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
225
226 auto conditionalBuffer = createConditionalRenderingBuffer(m_context, m_data);
227 //prepare command buffers
228 const bool useSecondaryCmdBuffer = m_data.conditionInherited || m_data.conditionInSecondaryCommandBuffer;
229
230 if (m_data.secondaryCommandBufferNested)
231 {
232 m_context.requireDeviceFunctionality("VK_EXT_nested_command_buffer");
233 const auto &features =
234 *findStructure<VkPhysicalDeviceNestedCommandBufferFeaturesEXT>(&m_context.getDeviceFeatures2());
235 if (!features.nestedCommandBuffer)
236 TCU_THROW(NotSupportedError, "nestedCommandBuffer is not supported");
237 }
238
239 VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = initVulkanStructure();
240 conditionalRenderingInheritanceInfo.conditionalRenderingEnable = m_data.conditionInherited ? VK_TRUE : VK_FALSE;
241
242 const VkCommandBufferInheritanceInfo inheritanceInfo = {
243 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
244 &conditionalRenderingInheritanceInfo,
245 VK_NULL_HANDLE, // renderPass
246 0u, // subpass
247 VK_NULL_HANDLE, // framebuffer
248 VK_FALSE, // occlusionQueryEnable
249 (VkQueryControlFlags)0u, // queryFlags
250 (VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
251 };
252
253 const VkCommandBufferBeginInfo commandBufferBeginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
254 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
255 &inheritanceInfo};
256
257 beginCommandBuffer(vkd, commandBuffer.get());
258 //transition color and depth images
259 VkImageMemoryBarrier colorTransition =
260 makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
261 colorAttachment.get()->get(), colorSubresourceRange);
262 VkImageMemoryBarrier depthTransition =
263 makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
264 depthAttachment.get()->get(), depthSubresourceRange);
265 VkImageMemoryBarrier barriers[] = {colorTransition, depthTransition};
266 cmdPipelineImageMemoryBarrier(vkd, commandBuffer.get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
267 VK_PIPELINE_STAGE_TRANSFER_BIT, barriers, DE_LENGTH_OF_ARRAY(barriers));
268
269 //clear to the incorrect color
270 vkd.cmdClearColorImage(commandBuffer.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColorWrong,
271 1, &colorSubresourceRange);
272 vkd.cmdClearDepthStencilImage(commandBuffer.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL,
273 &depthClearWrong, 1, &depthSubresourceRange);
274
275 const auto barrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
276 cmdPipelineMemoryBarrier(vkd, commandBuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
277 &barrier);
278
279 //do all combinations of clears
280 if (useSecondaryCmdBuffer)
281 {
282 if (m_data.secondaryCommandBufferNested)
283 {
284 vkd.beginCommandBuffer(*commandBuffer3, &commandBufferBeginInfo);
285 }
286
287 vkd.beginCommandBuffer(*commandBuffer2, &commandBufferBeginInfo);
288 if (m_data.conditionInSecondaryCommandBuffer)
289 {
290 beginConditionalRendering(vkd, commandBuffer2.get(), *conditionalBuffer, m_data);
291 }
292 else
293 {
294 beginConditionalRendering(vkd, commandBuffer.get(), *conditionalBuffer, m_data);
295 }
296
297 //clear to the correct colors
298 vkd.cmdClearColorImage(commandBuffer2.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColor,
299 1, &colorSubresourceRange);
300 vkd.cmdClearDepthStencilImage(commandBuffer2.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL,
301 &depthClear, 1, &depthSubresourceRange);
302
303 if (m_data.conditionInSecondaryCommandBuffer)
304 {
305 vkd.cmdEndConditionalRenderingEXT(commandBuffer2.get());
306 }
307 else
308 {
309 vkd.cmdEndConditionalRenderingEXT(commandBuffer.get());
310 }
311
312 vkd.endCommandBuffer(*commandBuffer2);
313 if (m_data.secondaryCommandBufferNested)
314 {
315 vkd.cmdExecuteCommands(commandBuffer3.get(), 1, &commandBuffer2.get());
316 vkd.endCommandBuffer(*commandBuffer3);
317 vkd.cmdExecuteCommands(commandBuffer.get(), 1, &commandBuffer3.get());
318 }
319 else
320 {
321 vkd.cmdExecuteCommands(commandBuffer.get(), 1, &commandBuffer2.get());
322 }
323 }
324 else
325 {
326 beginConditionalRendering(vkd, commandBuffer.get(), *conditionalBuffer, m_data);
327
328 //clear to the correct colors
329 vkd.cmdClearColorImage(commandBuffer.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColor,
330 1, &colorSubresourceRange);
331 vkd.cmdClearDepthStencilImage(commandBuffer.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL,
332 &depthClear, 1, &depthSubresourceRange);
333
334 vkd.cmdEndConditionalRenderingEXT(commandBuffer.get());
335 }
336 copyImageToBuffer(vkd, commandBuffer.get(), colorAttachment.get()->get(), (*outBuffer).get(), imageSize,
337 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
338 copyImageToBuffer(vkd, commandBuffer.get(), depthAttachment.get()->get(), (*outDepthBuffer).get(), imageSize,
339 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, 1, VK_IMAGE_ASPECT_DEPTH_BIT,
340 VK_IMAGE_ASPECT_DEPTH_BIT);
341
342 endCommandBuffer(vkd, commandBuffer.get());
343 submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), commandBuffer.get());
344
345 invalidateAlloc(vkd, device, outBufferAlloc);
346 invalidateAlloc(vkd, device, outDepthBufferAlloc);
347 tcu::ConstPixelBufferAccess outPixels(mapVkFormat(imageFormat), imageDim, outBufferData);
348 tcu::ConstPixelBufferAccess outDepth(mapVkFormat(depthFormat), imageDim, outDepthBufferData);
349
350 //the clears should happen in every case
351 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare color", "color image comparison",
352 expected, outPixels, tcu::Vec4(0.0), tcu::COMPARE_LOG_ON_ERROR))
353 return tcu::TestStatus::fail("Color image verification failed, check log for details");
354 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare depth", "depth image comparison",
355 expected, outDepth, tcu::Vec4(0.0), tcu::COMPARE_LOG_ON_ERROR))
356 return tcu::TestStatus::fail("Depth image verification failed, check log for details");
357
358 return tcu::TestStatus::pass("Pass");
359 }
360
361 } // namespace
362
363 // operations that ignore conditions
ConditionalIgnoreTests(tcu::TestContext & testCtx)364 ConditionalIgnoreTests::ConditionalIgnoreTests(tcu::TestContext &testCtx) : TestCaseGroup(testCtx, "conditional_ignore")
365 {
366 }
367
~ConditionalIgnoreTests(void)368 ConditionalIgnoreTests::~ConditionalIgnoreTests(void)
369 {
370 }
371
init(void)372 void ConditionalIgnoreTests::init(void)
373 {
374 for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
375 {
376 const ConditionalData &conditionData = conditional::s_testsData[conditionNdx];
377
378 if (conditionData.clearInRenderPass)
379 continue;
380
381 // tests that some clear operations always happen
382 addChild(new ConditionalIgnoreClearTestCase(
383 m_testCtx, std::string("clear_") + de::toString(conditionData).c_str(), conditionData));
384 }
385 }
386
387 } // namespace conditional
388 } // namespace vkt
389